email is an atom in the map you have posted there. If it were a string it would be:
%{"email" => ["Email has already been registered"]}
So when you call atom_tostring/1
(which I assume is just a wrapper around to_string/1
?), the pattern match will be:
{"email", [msg]} = %{email: ["Email has already been registered"]}
The pattern would match as: “A tuple of the string ‘email’ and an array of exactly one item”. What you want is “the value associated with the key :email, which is an array with exactly one item in it”:
%{email: [msg]} = %{email: ["Email has already been registered"]}
… and if you try that in iex
you’ll see that msg now is bound to the value “Email has already been registered”.
However… if there is more than one entry in that array, it still won’t match, and instead what may want is:
%{email: [msg | _]} = %{email: ["Email has already been registered"]}
That |
means “everything else after the first element in the list”, and the _
binds that “everything else” to the “ignore this” non-variable (meaning it just gets dropped). This will continue to match even multi-entry arrays:
> %{email: [msg | _]} = %{email: ["Email has already been registered", "Something else"]}
> msg
"Email has already been registered"
Of course, this will not match an empty array, so beware:
%{email: [msg | _]} = %{email: []}
** (MatchError) no match of right hand side value: %{email: []}
But there you go … hopefully that gets you a step further along 