我尝试将2条现有的多对多记录与ECTO和put_assoc / 4相关联,但在尝试更新时不会删除元素。
基本上,我有项目和用户。为了管理用户对项目的访问,我具有表“ user_project”。
def Project do
schema "project" do
...
# users (if user_type is :admin)
many_to_many(
:users,
User,
join_through: "user_project"
)
...
end
end
def User do
schema "user" do
...
# users (if user_type is :admin)
many_to_many(
:projects,
User,
join_through: "user_project"
)
...
end
...
def changeset_insert_not_active(%User{} = user, attrs) do
user
|> cast(attrs, @required_fields)
|> put_assoc(:projects, attrs.projects)
|> validate_required(@required_fields)
|> validate_user_type()
|> validate_format(:email, ~r/@/)
|> unique_constraint(:email)
end
...
def changeset_update_projects(%User{} = user, projects) do
user
|> cast(%{}, @required_fields)
# associate projects to the user
|> put_assoc(:projects, projects)
end
...
end
def Management do
...
def create_user(attrs \\ %{}, project_ids \\ []) when is_list(project_ids) do
projects =
Project
|> where([project], project.id in ^project_ids)
|> Repo.all()
%User{}
|> User.changeset_insert(attrs
|> Map.put(:projects, projects))
|> Repo.insert()
end
...
def upsert_user_projects(user, project_ids) when is_list(project_ids) do
projects =
Project
|> where([project], project.id in ^project_ids)
|> Repo.all()
user
|> User.changeset_update_projects(projects)
|> Repo.update()
end
...
end
当我创建带有项目列表的用户时,所有内容都会创建,但是当尝试更新用户项目时,删除对一个项目的访问权限就不会发生...
例如:
test "xxx" do
Management.upsert_user_projects(user, [1])
l = Management.list_user_project_by_user(user.id)
IO.puts("---------")
IO.puts("1 - length:#{length(l)}")
IO.puts("---------")
Enum.each(l, fn project ->
IO.inspect(project.project_id, label: "inserted project_id ")
end)
Management.upsert_user_projects(user, [2])
l = Management.list_user_project_by_user(user.id)
IO.puts("---------")
IO.puts("2 - length:#{length(l)}")
IO.puts("---------")
Enum.each(l, fn project ->
IO.inspect(project.project_id, label: "inserted project_id ")
end)
end
返回值:
---------
1 - length:1
---------
inserted project_id : 1
2 - length:2
---------
inserted project_id : 1
inserted project_id : 2
为什么?为什么put_assoc / 4只添加新元素而不删除?
答案 0 :(得分:1)
我认为您需要在关联上定义on_replace
选项:
https://hexdocs.pm/ecto/Ecto.Changeset.html#module-the-on_replace-option
答案 1 :(得分:1)
@IvanYurov是正确的。您需要定义on_replace选项,但也需要更新用户的预加载(在每个请求中)。基本上,为了使测试正确,您需要在Management.upsert_user_projects(user,...)之前执行一个user = get_user(带有项目的预加载)。
def get_user(id) do
Repo.get(User, id)
|> Repo.preload(:projects)
end