Get_field returning nil instead of my default

My schema has two numbers, they must add up to 100 on save.

The fields are simple field ... :integer with no defaults, etc.

I have a custom validator, to get the fields and sum them:

  defp validate_sum(changeset) do
    Enum.reduce([:part_a,  :part_b], 0,
      fn key, sum ->
        sum + (get_field(changeset, key, 0)) # drama generator
      end
    )
    |> case do
      100 ->
        changeset
      _ ->
        changeset
        |> add_error(:part_a, "sum of parts must be 100")
        |> add_error(:part_b, "sum of parts must be 100")
    end
  end

My problem is that get_field returns nil, not zero. I think because the key exists, but its value is nil?

I can solve my problem by writing (get_field(changeset, key) || 0), which returns the value if its not nil, or 0.

Is this the correct way of handling this? Is get_field intended to only return it’s “default” value if you try to access a non existent / misnamed field? Why would that be useful?

Seems like your analysis is correct.

Why would that be useful?

Since ecto can be used for schema-less data - see Schemaless changesets for instance.


Please note that both data and changes fields are “public fields”, so you can just check the field whether you have to run the validation and where to get the value (data vs changes).

Or you can use the value from data as the default value for get_change/3.

2 Likes

Man. The people who wrote Ecto are like… super smart…