Last active
August 16, 2017 15:54
-
-
Save xtian/06e9c0dcb1e201d18010d477a2645488 to your computer and use it in GitHub Desktop.
Ecto errors_on helper that returns atoms instead of strings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@doc """ | |
Helper for returning list of errors in a struct when given certain data. | |
## Examples | |
Given a User schema that lists `:name` as a required field and validates | |
`:password` to be safe, it would return: | |
iex> errors_on(%User{}, %{}) | |
[name: :required] | |
You could then write your assertion like: | |
assert {:name, :required} in errors_on(%User{}, %{}) | |
You can also create the changeset manually and retrieve the errors | |
field directly: | |
iex> changeset = User.changeset(%User{}, password: "password") | |
iex> {:password, "is unsafe"} in changeset.errors | |
true | |
""" | |
def errors_on(struct, data) do | |
struct.__struct__.changeset(struct, data) | |
|> Ecto.Changeset.traverse_errors(fn {_, opts} -> Keyword.pop(opts, :validation) end) | |
|> Enum.flat_map(fn {key, errors} -> for info <- errors, do: validation_info(key, info) end) | |
end | |
defp validation_info(key, {type, []}), do: {key, type} | |
defp validation_info(key, {type, opts}) do | |
opts = opts |> Keyword.drop([:count]) |> Enum.sort | |
{key, type, opts} | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@doc """ | |
A helper that transform changeset errors to a map of messages. | |
assert {:field_name, :invalid} in errors_on(%Schema{}, %{field_name: "bad value"}) | |
assert {:field_name, :invalid} in errors_on(changeset) | |
""" | |
def errors_on(struct, data), do: struct |> struct.__struct__.changeset(data) |> errors_on() | |
def errors_on(changeset) do | |
changeset | |
|> Ecto.Changeset.traverse_errors(fn _, _, {error_message, opts} -> | |
{validation_name, opts} = Keyword.pop(opts, :validation) | |
{validation_name || error_message, opts} | |
end) | |
|> Enum.flat_map(fn {field, errors} -> | |
for error <- errors, do: List.to_tuple([field | flatten_keyword_list(error)]) | |
end) | |
end | |
defp flatten_keyword_list(error), do: IO.inspect(error) | |
# defp flatten_keyword_list({key, list}) when is_list(list), do: [key | flatten_keyword_list(list)] | |
# defp flatten_keyword_list({key, value}), do: [key, value] | |
# defp validation_info(field, {nested_field, [{validation_name, []}]}) do | |
# {field, nested_field, validation_name} | |
# end | |
# defp validation_info(field, {nested_field, [{validation_name, opts}]}) do | |
# {field, nested_field, validation_name, filter_options(opts)} | |
# end | |
# defp validation_info(field, {validation_name, []}) do | |
# {field, validation_name} | |
# end | |
# defp validation_info(field, {validation_name, opts}) do | |
# {field, validation_name, filter_options(opts)} | |
# end | |
# defp filter_options([{_, _} | _] = opts), do: opts |> Keyword.drop([:count]) |> Enum.sort | |
# defp filter_options(opts), do: Enum.sort(opts) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment