Ecto удалить many_to_many объединение, сохраняя объединенные записи в такте - PullRequest
1 голос
/ 05 марта 2019

У меня есть две модели Ecto: User и Skill, которые объединены ассоциацией many_to_many через таблицу users_skills:

create table(:users_skills, primary_key: false) do
  add :user_id, references(:users, on_delete: :nothing)
  add :skill_id, references(:skills, on_delete: :nothing)
end

create unique_index(:users_skills, [:user_id, :skill_id])

В схеме User есть:

many_to_many :skills, Skill, join_through: "users_skills"

А в схеме Skill есть:

many_to_many :users, User, join_through: "users_skills"

Я хочу удалить навыки пользователя, не удаляя сам User или Skill. В настоящее время я пытаюсь это:

query = Ecto.assoc(current_user, :skills)
Repo.delete_all(query)

Однако выдает ошибку:

(foreign_key_violation) update or delete on table "skills" violates foreign key constraint "users_skills_skill_id_fkey" on table "users_skills"

При добавлении on_delete: :delete_all к миграции users_skills это приводит к нежелательному удалению связанных умений.

Как мне подойти к этому так, чтобы удалялась только запись ассоциации, а User и Skill оставались в такте?

1 Ответ

1 голос
/ 06 марта 2019

Я уверен, что есть лучшие способы сделать это, но вы можете передать опцию on_replace: :delete макросу many_to_many в ваших схемах.

defmodule User do
  use Ecto.Schema

  schema "users" do
    field(:name)
    many_to_many(:skills, Skill, join_through: "users_skills", on_replace: :delete)

    timestamps()
  end
end

Теперь, если вы запустите

current_user
|> Repo.preload(:skills)
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:skills, [])
|> Repo.update!()

Удаляет из таблицы users_skills, а таблица skills остается без изменений.

...