Exists any method to list all fields declared in "schema" of Ecto.Repo without redeclare?

I’m studying Ecto and I realized that if I want to cast all the fields that I have in my Schema I have to redeclare them, like this:

defmodule Apure.Schemas.User do
  use Ecto.Schema
  import Ecto.Changeset

  @fields [:display_name, :email, :password, :photo_url]

  schema "user" do
    field :display_name, :string
    field :email, :string
    field :password, :string
    field :photo_url, :string
  end

  def changeset(obj, params \\ %{}) do
    cast(obj, params, @fields)
  end
end

I believe that redeclaring all the fields that I included in the schema is an “over-engineering” problem, and that there should be some way to cast() all the fields, after all it doesn’t make sense to cast only some fields and let the database return a typing error

IMO it’s the contrary - introducing macros or similar “magic” to avoid typing one line of configuration is “over-engineering” the situation.

There are also many reason why you wouldn’t always want to cast every field:

  • some fields aren’t updatable - they are set when inserting and don’t change. A great way to make this clear in code is to have an update_changeset that doesn’t include them in cast

  • some fields are only ever written by “system” code, not via user input / forms / API requests. A great way to make this clear is to call put_change for them explicitly instead of mixing them into params

Even in your example there’s a case of the latter just on the horizon - when you move to storing password as a hashed value, you wouldn’t send the hashed_password column through cast.

3 Likes

I agree with everything that @al2o3cr said, adding that I think it’s always preferable to be explicit on what you cast.

but if you really want to avoid typing that… you can always use the schema reflections for that

cast(struct, params, __schema__(:fields))

https://hexdocs.pm/ecto/Ecto.Schema.html#module-reflection