#アソシエーションって何??
簡単に説明するとモデルを利用したテーブル同士の関連付けのことですね。
テーブル同士で関連付けておき、一方のモデルからもう一方のモデルに
アクセスできるようにするためということですね。
*今回は、「多対多」のアソシエーションの説明になります。
#関連付けを行う理由
Railsでは、「関連付け(アソシエーション: association)」とは2つの
Active Recordモデル同士の繋がりのことですね。
2つモデルの間には関連付けを行なう必要がありますが、
その理由を知っていますか?
それはですね、関連付けを行う事でコードの共通操作をより
シンプルで簡単にできるからなんです。
#例:アソシエーション(多対多)
今回は、usersテーブルとroomsテーブルで説明したいと思います。
まずは、テーブルごとに、他テーブルとの関係性を考えましょう。
・ユーザーがどのチャットルームに属しているかを管理する
・チャットルームにどのユーザーが存在するかを管理する
今回の下記の画像になります。
ここで注目すべきポイントは、usersテーブルとroomsテーブルの関係性が、
今回のDB設計では「多対多」という関係性が存在していますね。
「多対多」は、関連するテーブルのidをお互いが複数持っている関係性のことです。
今回の場合は、「一人のユーザーは複数のチャットルームに所属する」
「一つのチャットルームには複数ユーザーが所属する」という場合の関係性ですね。
しかしですね、このテーブルの関係性を示すために、外部キーへ複数の値を
保存できれば簡単なのですが、1つのカラムに対して複数の値を保存することはできません。
よく考えられる方法としては、関連するidが増えるごとにカラムを増やすという
パターンがあります。
例としてわかりやすいように下記に画像を載せておきますね。
画像を見てもらえるとわかるのですが、カラムを不安と
無駄なカラムが生じていますね。
このようなDB設計は、関連するレコードが増えるほどカラムが増えるため、
良くない設計とされているものですね。
これを解決するために使用するのが、中間テーブルです。
#中間テーブル
では、中間テーブルって何って思われると思うので簡単に説明します。
中間テーブルとは、その名の通り2つのテーブルの中間にあるテーブルのことです。
今回で言うと、usersテーブルとroomsテーブルの間に中間テーブルを作成します。
中間テーブルは、「多対多」の関係にある2つのテーブルの間に挟まって、2つの組み合わせパターンだけをレコードとして保存することですね。
また、2つのモデルのみでは「多対多」のアソシエーションを
組むことはできません。
そのため、中間テーブルを利用して「多対多」の関係を定義します。
まだこれだけの説明ではイメージがあまりできてないかもしれないので、
次はSNSに例えて説明します。
次の説明からはテーブル名を変えていきますので、先ほどのテーブル名とは異なります。わかりにくかったら申し訳ないです。。
#タグ付き写真投稿アプリを例に中間テーブルの役割を確認しましょう
『Instagram』などの、一つの写真に複数のタグ付けができる写真投稿アプリをイメージしてみて下さい。
『Instagram』のようにタグ付け機能を実現するには3つのテーブルが
必要です。タグを保存するテーブル、写真を保存するテーブル、
そして「どの写真にどのタグが登録されているか」を保存するテーブルです。
このうち写真やタグを保存するテーブルの名前はtagsテーブル、photosテーブルで良いでしょう。「どの写真にどのタグが ~」のテーブルは、photos_tagsテーブルとします。関係する2つのテーブルをアンダーバーで繋いだ名前です。
それぞれのテーブルに保存されているレコードの関係性は以下のようになります。
上記の画像の見てもらうとわかるのですが、中間テーブルには、「どの写真とタグが関連づいているか」という情報が記録されています。一つのレコードには「photo_id × tag_id」の組み合わせが記録され、すべての写真とタグの組み合わせの数だけ、レコードが蓄積されていきます。例えば、10個の写真にそれぞれ、異なるタグが3つずつ付いている場合、これらの関係性を表すための中間テーブルには30個のレコードが生成されることになります。
ここまでが、中間テーブルを用いて情報をDBに保存することの説明です。ここからは、中間テーブルを用いてアソシエーションを設定する方法を確認します。
中間テーブルを経由して「多対多」のテーブルへアソシエーションを組むには、これまで使用してきたhas_manyメソッドに、throughオプションを記述する必要があります。
throughオプションの説明を次にさせて頂きます。
#throughオプション
has_manyメソッドのthroughオプションは、モデルに多対多の関連を定義するときに利用します。
throughという名前のとおり、「〜を経由する」という意味です。
もっとわかりやすく参考画像を載せておきます。
throughオプションを使用し、多対多のアソシエーションを定義する場合は、それぞれのモデルに以下のような記述をします。
class Photo < ApplicationRecord
has_many :photos_tags
has_many :tags, through: :photos_tags
end
class Tag < ApplicationRecord
has_many :photos_tags
has_many :photos, through: :photos_tags
end
class PhotosTag < ApplicationRecord
belongs_to :photo
belongs_to :tag
end
多対多の関係にある2つのテーブルのモデルでは、has_manyメソッドによる「1対多」のアソシエーションを互いに定義するのと合わせて、
throughオプションによって経由する中間テーブルを指定します。
一方、中間テーブルのモデルでは、belongs_toメソッドで多対多の関係にある2つのテーブルを指定します。
以上が、「多対多」のアソシエーションを定義する方法です。
#まとめ
・「多対多」のアソシエーションには中間テーブルを用いること
・「多対多」の関係にある2つのテーブルのモデルでは、has_manyメソッド
による「1対多」のアソシエーションを互いに定義するのと合わせて、
throughオプションを使用して経由する中間テーブルを指定すること
今回の説明は、長くなってしまって説明がわかりにくくなっていたら、
すいません。。
私なりに頑張ってまとめたので参考になれば嬉しいです。
####以上。