【发布时间】:2021-05-30 10:03:51
【问题描述】:
我有两张桌子Users 和Companies。用户属于一个公司,一个公司有很多用户。
我有一个表单,我可以在其中将用户添加到公司,它被实现为嵌套表单 (inputs_for),所以在公司的变更集中,我调用了 cast_assoc
def changeset(company, attrs) do
company
|> cast(attrs, [:name, :email])
|> validate_required([:name, :email])
|> cast_assoc(:users, with: &User.company_admin_changeset/2)
end
我想要做的是,当我将已经存在的用户添加到公司时,它应该更新用户的 company_id(foreign_key)。如果用户不存在,只需创建一个。
看着我的要求,我开始认为不可能从 cast_assoc 中做到这一点。所以,我用了transaction
def create_company(attrs \\ %{}) do
Repo.transaction(fn ->
cmp =
Company.changeset(%Company{}, %{name: attrs["name"], email: attrs["email"]})
|> Repo.insert!()
Enum.each(attrs["users"], fn {_, user} ->
case Accounts.get_user_by_email(user["email"]) do
nil ->
User.company_admin_changeset(%User{}, %{email: user["email"], company_id: cmp.id})
|> Repo.insert!()
account ->
account |> Ecto.Changeset.change(company_id: cmp.id) |> Repo.update!()
end
end)
end)
end
但如果可能的话,你能告诉我该怎么做吗?
【问题讨论】:
-
我认为你的方法是正确的——你的用例似乎不属于协会
:on_replace选项所描述的那些。但是,您可以稍微清理一下流程以利用Ecto.Repo.get_by/3和Ecto.Repo.insert_or_update/2