2016-08-24 75 views
3

我有一个用户和程序模型,它具有多对多关联。 他们创建关联成功,让用户有很多程序(反之亦然),但现在我需要删除的关联(但不会删除的用户或程序)在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(和凤凰),所以任何帮助将不胜感激!

+0

您可以制作与您的连接表关联的Ecto模型/模式吗? 'defmodule MyApp.UserProgram做...' 与 '模式 “users_programs” 做...' 那么你可以使用外生的API来删除与匹配USER_ID和program_id的UserProgram。 – Bruce

+0

这也允许您轻松地将元数据添加到关联中(将来也许用户只会在某个特定日期之前与某个程序关联,因此您可以将一个expires_at字段添加到UserProgram架构并使用Ecto进行更新)。 – Bruce

+0

该功能是否真的只能在1个程序和1个用户之间添加关联?如果是这样,那看起来效率很低。这不应该超过3个查询,一个取得程序,一个取用户,一个在连接表中插入一个条目。我同意Bruce为连接表创建模式。 – Dogbert

回答

3

你可能会想看看Ecto.Schema.ManyToMany文档。有几个选项(直接从文档获取并重新格式化):

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

对我来说,相关位是关于删除数据的部分:https://hexdocs.pm/ecto/Ecto.Schema.html#many_to_many/3-removing-data – elkelk

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 

这不是在文档很清楚。