Skip to content

Instantly share code, notes, and snippets.

@TylerPachal
Last active July 23, 2021 19:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TylerPachal/6ac01f48239ab082d88792a97602602d to your computer and use it in GitHub Desktop.
Save TylerPachal/6ac01f48239ab082d88792a97602602d to your computer and use it in GitHub Desktop.
# An experiment to render a flat-list of nested errors.
#
# The default translate_errors() function would render (nested) errors like this:
# %{
# "pets" => [
# %{},
# %{"type" => ["is invalid"]},
# %{},
# %{"type" => ["is invalid"]}
# ]
# }
#
# With this implementation of the translate_errors() function, they are instead rendered like this:
# [
# %{
# "error" => "is invalid",
# "field" => "pets.1.type"
# },
# %{
# "error" => "is invalid",
# "field" => "pets.3.type"
# }
# ]
#
# Note that this code does not cover a lot of edge cases, and only works for certain embedded
# formats. See the implementation of Ecto.Changeset.traverse_errors() for an idea of other cases
# we are missing.
defmodule PhoenixPlaygroundWeb.ChangesetView do
use PhoenixPlaygroundWeb, :view
def render("error.json", %{changeset: changeset}) do
%{errors: translate_errors(changeset)}
end
def translate_errors(%Ecto.Changeset{errors: errors, changes: changes, types: types}, parent_path \\ []) do
current_errors(errors, parent_path) ++ nested_errors(types, changes, parent_path)
end
defp current_errors(errors, parent_path) do
Enum.map(errors, fn {key, error} ->
%{
field: Enum.join(parent_path ++ [key], "."),
error: translate_error(error)
}
end)
end
defp nested_errors(types, changes, parent_path) do
nested_types = for {type, {tag, %{cardinality: :many}}} when tag in [:embed, :assoc] <- types, do: type
Enum.reduce(nested_types, [], fn type, acc ->
changesets = Map.get(changes, type)
errors =
changesets
|> Enum.with_index()
|> Enum.flat_map(fn {changeset, index} ->
parent_path = parent_path ++ [type, index]
translate_errors(changeset, parent_path)
end)
acc ++ errors
end)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment