TIL Ecto schemaless changeset ignores params setting a value to nil

Today I stumbled upon behaviour that I find confusing.
I used schemaless changeset starting with empty data and trying to set a field f to nil.

iex(1)> c = Ecto.Changeset.cast({%{}, %{f: :string}}, %{"f" => nil}, [:f])
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: %{}, valid?: true>

I expected it to contain changes %{f: nil}.

It is not a bug. It is consistent with what the docs say. And the docs say that “empty values are converted to the fields default value” and it just happens that without struct there is no default value so nothing is set.

Do you think this is something worth adding to the docs?

2 Likes

FWIW, you can provide default values by making the map in the tuple a non-empty map. :slight_smile: In any case, improvements to the docs are always welcome!

5 Likes

Thanks!

iex(5)> Ecto.Changeset.cast({%{f: nil}, %{f: :string}}, %{"f" => nil}, [:f])
#Ecto.Changeset<
  action: nil,
  changes: %{},
  errors: [],
  data: %{f: nil},
  valid?: true
>

Indeed it solves the issue. Which again makes sense since this “imitates” struct initialization :slight_smile:

2 Likes