ecto cast_assoc查找或创建

时间:2016-11-13 23:56:29

标签: elixir phoenix-framework ecto

调用cast_assoc时,我想要一个'查找或创建'样式行为。在Ecto中有一种简单的方法吗?

作为一个人为的例子,user belongs_to是我最喜欢的coloruniquecolor.name。如果我创建一个已经存在喜欢的颜色的新用户,我会收到错误(name has already been taken)。相反,我想将user.color_id设置为预先存在的color记录。在Ecto中是否有内置功能来执行此操作,还是我必须自己推出解决方案?

用户变更集:

def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:name])
  |> cast_assoc(:color)
end

测试失败:

test "create user with pre-existing color" do
  Repo.insert!(%Color{name: "red"})

  %User{}
  |> User.changeset(%{name: "Jim", color: %{name: "red"}})
  |> Repo.insert!
end

1 个答案:

答案 0 :(得分:0)

使用它的方式,恐怕您将不得不编写自己的代码:在提供的示例中,您正在处理子assoc(用户),尝试管理其父(例如颜色)。这必须手动完成。

要添加的代码量实际上并不是那么大。用于创建用户的代码如下所示:

color = Repo.get_by(Color, name: params["color"]["name"])

if color do
  %User{}
  |> User.changeset(params)
  |> Ecto.Changeset.put_assoc(:color, color)
else
  %User{}
  |> User.changeset(params)
  |> Ecto.Changeset.cast_assoc(:color)
end
|> Repo.insert!

或者,您应该颠倒您的方法-如果您知道color提前存在(我认为应该存在),则可以执行以下操作:

color = Repo.get_by(Color, name: params["color"]["name"])

color
|> build_assoc(:user)

这当然需要颜色在其架构中声明has_one :user, Userhas_many :users, User关联。