如何在嵌套变更集上使用 add_error?

How to use add_error on a nested changeset?

根据我在documentation for 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: &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 向嵌套 :person 属性内的 :other_field_made_to_fail 添加错误并保持变更集的其余部分完整?

我设法弄明白了。如果有其他人感兴趣,解决方案是在您的变更集上调用 update_change/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 对嵌套变更集执行其他变更集功能,它将 return 更新的嵌套变更集。