Defining read-only fields in Ecto Schema

This is a perfect scenario for two changeset functions!

def changeset(struct, params) do
  struct
  |> cast(params, list_of_all_fields())
  |> validation_one()
  |> validation_two()
end

def update_changeset(struct, params) do
  struct
  |> cast(params, list_of_updateable_fields())
  |> validation_three()
  |> validation_four()
end

Never feel like you have to pack everything into a single changeset function. You can always create as many as you need for a given module.