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?
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