2
votes

I've got an Ecto Model with a changeset that will change a state property in a model:

def next_state_changeset(model, params) do
   model
   |> cast(params, ~w(state))
   |> validate_required(:state)
end

However I'd like to reject a changeset if the state submitted is the same as in the model (there is no change in the state)
But this code will still return a valid changeset if there is no state submitted, because if it doesn't exists in a changeset it still does in the model.

I know I could validate if the field is submitted in params with something like:
if params["state"] && model.state != params["state"] do ...
But I'd assume there are some Ecto functions to handle requirements like that

Sidenote:
If anyone of team Ecto sees that: I think that it should be more explicit in the docs that validate_required checks in the model too.

enter image description here

Because I feel like it's a little bit misleading

1
hexdocs.pm/ecto/Ecto.Changeset.html#change/2 You can use it and look for changes - Haito

1 Answers

1
votes

When a value of a field has changed, all validations (validate_required, validate_inclusion, etc) will operate on the new value. So I would just write a validator, that makes changeset invalid, if a field's value didn't change.

def next_state_changeset(model, params) do
  model
  |> cast(params, ~w(state))
  |> validate_changed(:state)
  |> validate_required(:state)
end

def validate_changed(cs, field) do
  if Map.has_key?(cs.changes, field) do
    cs
  else
    add_error(cs, field, "didn't change")
  end
end