al2o3cr
`Ecto.Changeset.validate_change` and setting fields to `nil`
Question / comment / maybe bug report
I was surprised that this didn’t work:
def validate_not_cleared(changeset) do
validate_change(changeset, :some_field, fn _, _new_value ->
if changeset.data.some_field do
[some_field: "can't be changed once set"]
else
[]
end
end)
end
It successfully adds an error to the changeset when some_field is being changed to a non-nil value, but if the changeset is clearing the value it doesn’t run:
%SomeStruct{some_field: "foo"}
|> Ecto.Changeset.change(%{foo: nil})
|> validate_not_cleared()
# gives valid?: true
Here’s what I’m using instead, for the moment:
def validate_not_cleared(changeset) do
case fetch_change(changeset, :some_field) do
{:ok, _new_value} ->
if changeset.data.some_field do
add_error(changeset, :some_field, "can't be changed once set")
else
changeset
end
:error ->
changeset
end
end
EDIT: this is also distinct from how Ecto.Changeset.update_change works, which uses fetch_change…
Most Liked
josevalim
As the docs say (emphasis mine):
It invokes the
validatorfunction to perform the validation only if a change for the givenfieldexists and the change value is notnil.
https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_change/3
That’s because most validations do not want to run on nil. You have one of the few exceptions. ![]()
al2o3cr
Oops, that was a typo between the real code and the sanitized-for-public consumption version! Good catch!







