#elixir #ecto
Вопрос:
Из того, что я понимаю в документации по add_error, это может относиться только к набору изменений верхнего уровня.
Однако как я могу использовать add_error для вложенного набора изменений?
Например, возьмем эти схемы:
defmodule MyApp.Person do
use Ecto.Schema
import Ecto.Changeset
schema "people" do
field :first_name, :string
field :last_name, :string
field :other_field_made_to_fail, :string
has_many :addresses, MyApp.Address
end
def changeset(person, attrs) do
person
|> cast(attrs, [:first_name, :last_name, :other_field_made_to_fail])
|> validate_required([:first_name, :last_name])
end
end
defmodule MyApp.Address do
use Ecto.Schema
import Ecto.Changeset
schema "addresses" do
field :street_name, :string
field :city, :string
field :state, :string
belongs_to :person, MyApp.Person
end
def changeset(address, attrs) do
address
|> cast(attrs, [:street_name, :city, :state])
|> validate_required([:city, :state])
|> cast_assoc(:person, with: amp;MyApp.Person.changeset/2, required: true)
end
end
И возьмите этот ввод данных:
%{
"address" => %{
"city" => "Test City",
"state" => "Test State",
"person" => %{
"first_name" => "John",
"last_name" => "Doe"
}
}
}
И этот результирующий набор изменений:
#Ecto.Changeset<
changes: %{
address: #Ecto.Changeset<
changes: %{
city: "Test City",
state: "Test State"
person: #Ecto.Changeset<
changes: %{
first_name: "John",
last_name: "Doe"
}
>
},
errors: []
valid?: true
>
}
>
Как бы я использовал add_error/4
, чтобы добавить ошибку :other_field_made_to_fail
внутрь вложенного :person
атрибута и сохранить оставшуюся часть набора изменений нетронутой?
Комментарии:
1. Зачем вам вообще понадобилось обрабатывать это с помощью самой внешней схемы? Ошибка должна быть добавлена во
MyApp.Person.changeset/2
время проверкиPerson
, чтобы она распространяласьcast_assoc/2
и могла быть обработанаEcto.Changeset.traverse_errors/2
позже.2. @AlekseiMatiushkin, потому
:other_field_made_to_fail
что это не является частью пользовательского ввода. Я хотел вызвать ошибку в этом поле на основе остальной части ввода пользователя. Это означает, что мне нужно вмешаться в набор изменений вместо того, чтобы позволить Ecto идти своим чередом.
Ответ №1:
Мне удалось это выяснить. В случае, если есть другие заинтересованные люди, решение состоит в том, чтобы вызвать update_change/3 в вашем наборе изменений и вызвать функцию в качестве 3-го аргумента, представляющего ваш вложенный набор изменений:
Ecto.Changeset.update_change(changeset, :person, fn person_changeset ->
Ecto.Changeset.add_error(person_changeset, :other_field_made_to_fail, "error message here")
end)
Конечным результатом является обновленный Address
набор изменений, который теперь включает Person
набор изменений с ошибкой в нем.
Вы также можете использовать update_change/3
для выполнения других функций набора изменений во вложенных наборах изменений, и он вернет обновленный вложенный набор изменений.