1

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?

1 Answer 1

3

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.