问题描述
我尝试将2条现有的多对多记录与ECTO和put_assoc/4相关联,但是在尝试更新时不会删除元素.
I try associate 2 existing Many-to-Many records with ECTO and put_assoc/4 but won't remove elements when try update.
基本上,我有项目和用户.为了管理用户对项目的访问,我具有表"user_project".
Basically i have projects and users . for manage the access of users to projects i have the table "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
当我创建带有项目列表的用户时,所有内容都会创建,但是当尝试更新用户项目时,删除对一个项目的访问权限就不会发生...
When i create user with list of projects is everything created but when try update the user projects removing the access to one project nothing happens ...
例如:
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只添加新元素却不删除?
Why? Why put_assoc/4 just add new elements don't remove?
推荐答案
@IvanYurov是正确的.您需要定义on_replace选项,但也需要更新用户的预加载(在每个请求中).基本上,为了使测试正确,您需要在Management.upsert_user_projects(user,...)之前执行一个user = get_user(带有项目的预加载).
@IvanYurov are right . You need to define on_replace option but also need the preloads of user updated (in every request). Basiclly for your test to be correct you need to do a user=get_user (with the preload of the projects) before Management.upsert_user_projects(user, ...).
def get_user(id) do
Repo.get(User, id)
|> Repo.preload(:projects)
end
这篇关于与ECTO和put_assoc/4进行多对多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!