It works, but the problem is - how to get nested errors. Let me explain:
Imagine, we have two models: Faculty, Speciality
Faculty
simple model with one required field(
title), length >= 6
defmodule Universities.Faculty do
use Universities.Web, :model
schema "faculties" do
field :title, :string
timestamps
has_many :specialities, Universities.Speciality
end
def changeset(model, params, assoc, opts \\ []) do
model
|> cast(params, [:title])
|> cast_assoc(assoc, opts)
|> validate_required([:title])
|> validate_length(:title, min: 6)
end
end
Specialitysimple model with one required field(
title), length >= 10
defmodule Universities.Speciality do
use Universities.Web, :model
schema "specialities" do
field :title, :string
timestamps
belongs_to :faculty, Universities.Faculty
end
def changeset(model, params \\ %{}) do
model
|> cast(params, [:faculty_id, :title])
|> validate_required([:title])
|> validate_length(:title, min: 10)
end
end
Faculty can have many
Specialities.
I need to validate and send response with errors if invalid.
Cases
1. Insert single Faculty and no Specialities, valid one
changeset = Faculty.changeset(%Faculty{}, %{title: "Faculty title"}, :specialities, [])
Valid, no errors.
2. Insert single Faculty and no Specialities, invalid one
changeset = Faculty.changeset(%Faculty{}, %{title: "Fac"}, :specialities, []) Invalid, length error. So, I traverse errors and send response:
%{errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)}
Client receives:
errors = {
title: "should be at least 6 character(s)"
}Works great.
3. Insert single Faculty and some Specialities, valid one's
changeset = Faculty.changeset(%Faculty{}, %{title: "Faculty", specialities: [
%{title: "Speciality one"},
%{title: "Speciality two"}
]}, :specialities, [])
Valid, no errors
4. [The problem one] Insert single Faculty and some Specialities, invalid one's
changeset = Faculty.changeset(%Faculty{}, %{title: "Faculty", specialities: [
%{title: "Short one"},
%{title: "Speciality two"}
]}, :specialities, [])Invalid,
first Speciality length error. If I use the same traverse function:
%{errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)}
I will get:
%{errors: %{specialities: [%{}, %{}]}}
So,
nested errors are not shown.
The expected output is:
errors = {
specialities: [
{
title: "should be at least 10 character(s)"
}
]
}That's why the question:
How to traverse and send the output with translated errors in it?