Romeo Mihalcea
Romeo Mihalcea

Reputation: 10262

Ecto changeset add multiple errors

I have a config map that I want to validate inside a changeset. The config has multiple keys and each of them has some constraints.

I could run a validator for each of them when data is received but this forces me to write a lot of code which can be done smarter so I'm running a loop and trying to gather all failed validations instead of running them one by one.

defp validate_config_flags(changeset) do
    config = get_field(changeset, :config)

    for  {k, v} <- config  do
        if !Map.has_key?(@config_flags, k) || !validate_config_flag(k, v) do
            add_error(changeset, :"#{k}", "Invalid value for `#{k}`")
        end
    end

    changeset
end

Obv my problem is that I return changeset even though certain fields fail and my question is related to that. How do I add more than one error message/failed validation to the result instead of returning at the first add_error somehow?

Upvotes: 1

Views: 1270

Answers (1)

Dogbert
Dogbert

Reputation: 222388

Most of the times when you want to repeatedly modify a term in Elixir, you're looking for Enum.reduce/3:

defp validate_config_flags(changeset) do
  Enum.reduce(get_field(changeset, :config), changeset, fn {k, v}, changeset ->
    if !Map.has_key?(@config_flags, k) || !validate_config_flag(k, v) do
      add_error(changeset, :"#{k}", "Invalid value for `#{k}`")
    else
      changeset
    end
  end)
end

This code is equivalent to yours but it keeps track of the new changeset returned by add_error at every step, similar to the following if Elixir had mutable variables:

for {k, v} <- config  do
  if !Map.has_key?(@config_flags, k) || !validate_config_flag(k, v) do
    changeset = add_error(changeset, :"#{k}", "Invalid value for `#{k}`")
  end
end

Upvotes: 3

Related Questions