6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アソシエーション(多対多)!!

Posted at

#アソシエーションって何??:information_desk_person_tone2:
簡単に説明するとモデルを利用したテーブル同士の関連付けのことですね。
テーブル同士で関連付けておき、一方のモデルからもう一方のモデルに
アクセスできるようにするためということですね。

*今回は、「多対多」のアソシエーションの説明になります。

#関連付けを行う理由

Railsでは、「関連付け(アソシエーション: association)」とは2つの
Active Recordモデル同士の繋がりのことですね。

2つモデルの間には関連付けを行なう必要がありますが、
その理由を知っていますか?

それはですね、関連付けを行う事でコードの共通操作をより
シンプルで簡単にできるからなんです。

#例:アソシエーション(多対多)

今回は、usersテーブルとroomsテーブルで説明したいと思います。

まずは、テーブルごとに、他テーブルとの関係性を考えましょう。

・ユーザーがどのチャットルームに属しているかを管理する
・チャットルームにどのユーザーが存在するかを管理する

今回の下記の画像になります。

多対多.png

ここで注目すべきポイントは、usersテーブルとroomsテーブルの関係性が、
今回のDB設計では「多対多」という関係性が存在していますね。
「多対多」は、関連するテーブルのidをお互いが複数持っている関係性のことです。

今回の場合は、「一人のユーザーは複数のチャットルームに所属する」
「一つのチャットルームには複数ユーザーが所属する」という場合の関係性ですね。

しかしですね、このテーブルの関係性を示すために、外部キーへ複数の値を
保存できれば簡単なのですが、1つのカラムに対して複数の値を保存することはできません。

よく考えられる方法としては、関連するidが増えるごとにカラムを増やすという
パターンがあります。
例としてわかりやすいように下記に画像を載せておきますね。

無駄なカラム.png

画像を見てもらえるとわかるのですが、カラムを不安と
無駄なカラムが生じていますね。

このようなDB設計は、関連するレコードが増えるほどカラムが増えるため、
良くない設計とされているものですね。

これを解決するために使用するのが、中間テーブルです。

#中間テーブル

では、中間テーブルって何って思われると思うので簡単に説明します。
中間テーブルとは、その名の通り2つのテーブルの中間にあるテーブルのことです。

今回で言うと、usersテーブルとroomsテーブルの間に中間テーブルを作成します。

中間テーブルは、「多対多」の関係にある2つのテーブルの間に挟まって、2つの組み合わせパターンだけをレコードとして保存することですね。

また、2つのモデルのみでは「多対多」のアソシエーションを
組むことはできません。
そのため、中間テーブルを利用して「多対多」の関係を定義します。

中間テーブル.png

まだこれだけの説明ではイメージがあまりできてないかもしれないので、
次はSNSに例えて説明します。
次の説明からはテーブル名を変えていきますので、先ほどのテーブル名とは異なります。わかりにくかったら申し訳ないです。。

#タグ付き写真投稿アプリを例に中間テーブルの役割を確認しましょう

『Instagram』などの、一つの写真に複数のタグ付けができる写真投稿アプリをイメージしてみて下さい。
『Instagram』のようにタグ付け機能を実現するには3つのテーブルが
必要です。タグを保存するテーブル、写真を保存するテーブル、
そして「どの写真にどのタグが登録されているか」を保存するテーブルです。

このうち写真やタグを保存するテーブルの名前はtagsテーブル、photosテーブルで良いでしょう。「どの写真にどのタグが ~」のテーブルは、photos_tagsテーブルとします。関係する2つのテーブルをアンダーバーで繋いだ名前です。

それぞれのテーブルに保存されているレコードの関係性は以下のようになります。

instagram.png

上記の画像の見てもらうとわかるのですが、中間テーブルには、「どの写真とタグが関連づいているか」という情報が記録されています。一つのレコードには「photo_id × tag_id」の組み合わせが記録され、すべての写真とタグの組み合わせの数だけ、レコードが蓄積されていきます。例えば、10個の写真にそれぞれ、異なるタグが3つずつ付いている場合、これらの関係性を表すための中間テーブルには30個のレコードが生成されることになります。

ここまでが、中間テーブルを用いて情報をDBに保存することの説明です。ここからは、中間テーブルを用いてアソシエーションを設定する方法を確認します。

中間テーブルを経由して「多対多」のテーブルへアソシエーションを組むには、これまで使用してきたhas_manyメソッドに、throughオプションを記述する必要があります。
throughオプションの説明を次にさせて頂きます。

#throughオプション

has_manyメソッドのthroughオプションは、モデルに多対多の関連を定義するときに利用します。
throughという名前のとおり、「〜を経由する」という意味です。
もっとわかりやすく参考画像を載せておきます。

参考.png

throughオプションを使用し、多対多のアソシエーションを定義する場合は、それぞれのモデルに以下のような記述をします。

models/photo.rb
class Photo < ApplicationRecord
  has_many :photos_tags
  has_many :tags, through: :photos_tags
end
models/tag.rb
class Tag < ApplicationRecord
  has_many :photos_tags
  has_many :photos, through: :photos_tags
end
models/photos_tag.rb
class PhotosTag < ApplicationRecord
  belongs_to :photo
  belongs_to :tag
end

多対多の関係にある2つのテーブルのモデルでは、has_manyメソッドによる「1対多」のアソシエーションを互いに定義するのと合わせて、
throughオプションによって経由する中間テーブルを指定します。

一方、中間テーブルのモデルでは、belongs_toメソッドで多対多の関係にある2つのテーブルを指定します。

以上が、「多対多」のアソシエーションを定義する方法です。

#まとめ

・「多対多」のアソシエーションには中間テーブルを用いること
・「多対多」の関係にある2つのテーブルのモデルでは、has_manyメソッド
による「1対多」のアソシエーションを互いに定義するのと合わせて、
throughオプションを使用して経由する中間テーブルを指定すること

今回の説明は、長くなってしまって説明がわかりにくくなっていたら、
すいません。。
私なりに頑張ってまとめたので参考になれば嬉しいです。

####以上。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?