Programmatic changeset errors

Is there a way to programmatically check for the existence of a specific changeset error?

If I am adding an error to the changeset like this:

      Ecto.Changeset.add_error(
        changeset,
        :age,
        "Must be more than 12"
      )

After I get the changeset back from Repo.insert how can I check that this specific error has been added? I want to add special handling for a specific error. I can use Ecto.Changeset.traverse_errors but that would require looking for the string "Must be more than 12" which seems brittle.

Default validators use additional keys to specify the type of the validation, you can do the same

{%{}, %{age: :integer}}
|> cast(%{}, [:age])
|> validate_required(:age)
|> add_error(:age, "Must be more than 12", validation: :too_young)

#Ecto.Changeset<
  action: nil,
  changes: %{},
  errors: [
    age: {"Must be more than 12", [validation: :too_young]},
    age: {"can't be blank", [validation: :required]}
  ],
  data: %{},
  valid?: false
>
1 Like

Hmmm, so I’d have a check like this:

case insert(changest) do
  {:ok, data} -> handle_data(data)
  {:error, changeset} ->
    if too_young_error?(changeset) do
      special_handling(changeset)
    else
      {:error, changeset}
    end
end

...
def too_young_error?(changeset) do
  Enum.any(changeset.errors, fn {key, {_error_message, keys} ->
    Keyword.get(keys, :validation) == :too_young
  end)
end

This is better than checking for the error message, but it would be nice to have a more straightforward way to do this check.

1 Like