I was playing around with for
this morning, iterating over a list of maps:
errors = [
%{title: ["should be at least 3 characters"]},
%{description: ["must provide a description", "another issue"]}
]
It’s cool that you can treat for
almost like a pipeline, to loop over each one of the above errors and then loop over the lists inside of them. But I’m curious why this works:
for errors <- errors, {_, error_list} <- errors, err <- error_list do
IO.inspect(err)
end
but this does not:
for {_, error_list} <- errors, err <- error_list do
IO.inspect(err)
end
To my thinking the first error <- errors
is redundant?
1 Like
for error_map <- errors,
{_key, error_list} <- error_map,
err_string <- error_list do
IO.inspect(err_string)
end
maybe this makes it more clear?
Edit: I notice now the data format is a little weird. You use one map per key, which is unnecessary and causing the code to be less clear. The errors could be in a single map/keyword e.g.
errors = %{
title: ["should be at least 3 characters"],
description: ["must provide a description", "another issue"]
}
which would allow you to use the simpler two-step for
that currently doesn’t work
2 Likes
Thanks @APB9785, I think I spent too long looking at this, yeah I see how error_map <- errors
is working in the little “pipeline”.
Maybe I overthought this, that errors
is what I assumed the output of Ecto.Changeset.traverse_errors/2
would be based on their docs. But I haven’t tested this with multiple errors on a changeset so maybe my input would look different?
[
email: {"can't be blank", [validation: :required]},
firstname: {"can't be blank", [validation: :required]},
lastname: {"can't be blank", [validation: :required]}
]
The above discussed for
works with this but now that I’ve released it’s a keyword list I think I’ll find a better way of handling this.
1 Like
It’s important to understand that a keyword list is syntactic sugar for a list of 2-element tuples (and furthermore the first element is an atom). You can break this down with a single generator in a for comprehension. Depending on your overall goal, you can process these easily, for example, to concat the field and the error message:
iex(1)> errors = [
...(1)> email: {"can't be blank", [validation: :required]},
...(1)> firstname: {"can't be blank", [validation: :required]},
...(1)> lastname: {"can't be blank", [validation: :required]}
...(1)> ]
[
email: {"can't be blank", [validation: :required]},
firstname: {"can't be blank", [validation: :required]},
lastname: {"can't be blank", [validation: :required]}
]
iex(2)> for {field, {message, _kw_option}} <- errors, do: "#{field} #{message}"
["email can't be blank", "firstname can't be blank",
"lastname can't be blank"]
3 Likes