Многие ко многим с ECTO и put_assoc / 4 - PullRequest
0 голосов
/ 25 января 2019

Я пытаюсь связать 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 просто добавляет новые элементы, а не удаляет?

Ответы [ 2 ]

0 голосов
/ 28 января 2019

@ ИванЮров прав.Вам необходимо определить параметр on_replace, но также необходимо обновить предварительные загрузки пользователя (в каждом запросе).В основном, чтобы ваш тест был корректным, вам нужно выполнить user = get_user (с предварительной загрузкой проектов) перед Management.upsert_user_projects (user, ...).

def get_user(id) do
  Repo.get(User, id)
  |> Repo.preload(:projects)
end
0 голосов
/ 26 января 2019

Я думаю, вам нужно определить on_replace параметр для ассоциации:

https://hexdocs.pm/ecto/Ecto.Changeset.html#module-the-on_replace-option

...