删除Ecto中的关联(对于多对多)

时间:2016-08-24 15:38:55

标签: elixir phoenix-framework ecto

我有一个用户和程序模型,它具有多对多关联。 他们成功创建了关联,因此用户有很多程序(反之亦然),但现在我需要删除关联(但不删除用户或程序)

我在ProgramController中有一个函数关联它们:

# Myapp.ProgramController

def associate_user(conn, _params) do
   %{"_csrf_token" => _csrf_token,"_method"=>_method,"_utf8" => _utf8,"id" => id, "user" => %{"email" => email}} = _params
   {pid, _} = Integer.parse(id)

   user = Repo.get_by(User, email: email) |> Repo.preload(:programs)
   program = Repo.get_by(Program, id: pid) |> Repo.preload(:users)

   pid_list = user.programs
   |> Enum.map(fn x -> x.id end)
   |> List.insert_at(0, program.id)

   changeset_list = from(program in Myapp.Program, where: program.id in ^pid_list)
   |> Repo.all
   |> Enum.map(&Ecto.Changeset.change/1)

   from(user in User, where: user.email == ^user.email, preload: [:programs, :role])
   |> Repo.one
   |> User.changeset(%{})
   |> Ecto.Changeset.put_assoc(:programs, changeset_list)
   |> Repo.update!

   program = conn.assigns[:program]
   changeset = Program.changeset(program)

   conn
   |> put_flash(:info, "Program updated successfully.")
   |> redirect(to: program_path(conn, :edit, program))
 end

我有一个创建连接表的迁移

defmodule Myapp.Repo.Migrations.AssociateUsersAndPrograms do
  use Ecto.Migration

  def change do

    alter table(:users) do
       add :current_program_id, references(:programs, on_delete: :nilify_all)
    end

    create table(:users_programs, primary_key: false) do
      add :user_id, references(:users, on_delete: :delete_all)
      add :program_id, references(:programs, on_delete: :delete_all)
    end

    create index(:users_programs, [:user_id])
  end
end

我如何解除特定用户与程序的关联,因为我在Ecto.Docs中没有看到delete_assoc?

到目前为止仍在学习和爱好Elixir(和凤凰城),所以任何帮助都会非常感激!

2 个答案:

答案 0 :(得分:5)

您可能希望查看Ecto.Schema.ManyToMany文档。有几个选项(直接从文档中采取和重新格式化):

  1. :on_delete - 删除父记录时对关联采取的操作。
  2. :nothing(默认)
  3. :delete_all - 只会从联接源中删除数据,而不会删除关联的记录。注意:创建引用时,也可以在迁移中设置on_delete。如果支持,则首选通过迁移依赖数据库。除非通过数据库迁移进行设置,否则:nilify_all:delete_all不会级联到子记录。

答案 1 :(得分:2)

查看Ecto's documentation上的on_replace属性。 您只需要使用on_replace属性标记该字段并像以前一样调用Ecto.Changeset.put_assoc,如下所示:

  schema "users" do
    ...
    many_to_many :programs, Program, join_through: "users_programs", on_replace: :delete
    ...
end

文档上并不是很清楚。