elixir - ectocast_assoc 查找或创建

标签 elixir phoenix-framework ecto

调用cast_assoc时,我想要“查找或创建”风格的行为。在 Ecto 中有一个简单的方法可以做到这一点吗?

作为一个人为的示例,user belongs_to最喜欢的color ,即unique通过color.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

最佳答案

按照你的说法,恐怕你必须滚动自己的代码:在提供的示例中,你正在处理子关联(用户),尝试管理它的父级(例如颜色)。这必须手动完成。

不过要添加的代码量其实并没有那么大。用户创建的代码如下所示:

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)

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

关于elixir - ectocast_assoc 查找或创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40580151/

相关文章:

elixir - 如何为 Phoenix 请求强制执行 JSON 编码?

mysql - 在 Ecto/Phoenix 中用微秒断言时间戳等于 mysql 数据库值

elixir - 如何 Enum 获取 ecto 成员 Elixir phoenix 的索引

elixir - Phoenix 的错误处理

elixir - Phoenix Framework - 表单中的确认字段

elixir - 使用 Elixir 和 Phoenix 框架形成对象

使用 Bamboo 而不是凤凰的电子邮件模板

pattern-matching - 模式匹配中 byte_size 的语法是什么?

datetime - Elixir 中以小时为单位的 2 个 DateTime 之间的差异

elixir - 如何通过 iex 显示命名函数的类型规范