Ecto - 如何使assoc_constraint返回与validate_required相同的错误?

时间:2016-07-28 11:45:15

标签: elixir ecto

假设我有Post belongs_to的模型Category

defmodule MyApp.Post do
  use MyApp.Web, :model

  schema "posts" do
    field :title, :string
    belongs_to :category, MyApp.Category
  end

  def changeset(model, params) do
    model
    |> cast(params, [:title, :category_id)
    |> validate_required([:title, :category_id])
    |> assoc_constraint(:category)
  end
end

问题是:如果我没有将category_id传递给params,则更改集错误键为:category_id,但在assoc_constraint失效时(如果类别不存在),我有category键。这对我来说有点懊悔 - 因为问题实际上是相同的 - 没有帖子类别。我该如何处理?

1 个答案:

答案 0 :(得分:0)

在阅读Ecto的源代码后,我能找到的唯一方法就是将错误中的名称作为字段提供给assoc_constraint,然后自己覆盖约束名称。 belongs_to约束的默认名称是#{table name}_#{column in table}_fkeysource)。

修改:如果我们自己传递foreign_key_constraint,我们也可以使用:name,因为assoc_constraint唯一没有foreign_key_constraint做的事情。我已经更新了以下代码。

迁移:

defmodule MyApp.Repo.Migrations.CreateComment do
  use Ecto.Migration

  def change do
    create table(:comments) do
      add :post_id, references(:posts, on_delete: :nothing)
      timestamps()
    end
    create index(:comments, [:post_id])
  end
end

型号:

def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:post_id])
  |> validate_required([:post_id])
  |> foreign_key_constraint(:post_id, name: :comments_post_id_fkey)
end

演示:

iex(1)> Comment.changeset(%Comment{}, %{}).errors
[post_id: {"can't be blank", []}]
iex(2)> Comment.changeset(%Comment{}, %{post_id: 999}).errors
[]
iex(3)> {:error, changeset} = Comment.changeset(%Comment{}, %{post_id: 999}) |> Repo.insert; changeset.errors
[post_id: {"does not exist", []}]
iex(4)> Comment.changeset(%Comment{}, %{post_id: 1}) |> Repo.insert
{:ok,
 %MyApp.Comment{__meta__: #Ecto.Schema.Metadata<:loaded, "comments">,
  id: 1, inserted_at: #Ecto.DateTime<2016-07-29 06:25:24>,
  post: #Ecto.Association.NotLoaded<association :post is not loaded>,
  post_id: 1, updated_at: #Ecto.DateTime<2016-07-29 06:25:24>}}