2016-08-24 2 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が見つかりませんでしたか?

まだエリクサー(とフェニックス)を学んでいて、これまでどんな助けでも大歓迎です!

+0

あなたの参加テーブルにEctoモデル/スキーマを関連付けることはできますか? 'defmodule MyApp.UserProgramない...' ' スキーマを持つ は、その後、あなたが一致するUSER_IDとPROGRAM_IDでUserProgramを削除するには、エクトのAPIを使用することができます...' を行う "users_programs"。 – Bruce

+0

これにより、関連付けにメタデータを簡単に追加することもできます(特定の日付まではユーザーがプログラムに関連付けられているため、UserProgramスキーマにexpires_atフィールドを追加し、Ectoを使用して更新できます)。 – Bruce

+0

この機能は実際には1つのプログラムと1人のユーザーの間の関連付けを追加するだけですか?もしそうなら、それは本当に非効率的に見えます。これは3つ以上のクエリを取るべきではなく、1つはプログラムをフェッチし、1つはユーザをフェッチし、もう1つは結合テーブルにエントリを挿入します。 Bruceはjoinテーブルのスキーマを作成することに同意します。 – 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プロパティを確認してください。

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

それは、ドキュメント上の非常に明確ではありません: あなただけon_replaceプロパティでフィールドをマークすると、あなたは、このような何かをやっているようEcto.Changeset.put_assocを呼び出す必要があります。

関連する問題