アソシエーション（多対多）！！

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

<font color="OrangeRed">＊今回は、「多対多」のアソシエーションの説明になります。</font>

#関連付けを行う理由

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

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

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

#例:アソシエーション（多対多）

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

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

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

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

![多対多.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762918/bae0029c-5ba2-875a-35e1-61b99c6bb081.png)


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

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

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

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


![無駄なカラム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762918/8897e2a5-e7bb-00e5-8f96-e7ce234d9be4.png)

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

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

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

#中間テーブル

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

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

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

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


![中間テーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762918/0fddf4c8-6d5d-634f-d07a-0f9b133ac802.png)

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

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


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

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

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

![instagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762918/53d6c455-6716-8b1a-58b3-eee089547f8f.png)


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

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

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


#throughオプション

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

![参考.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762918/628cc16f-2023-5595-ac7e-37aca2d287b3.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オプションを使用して経由する中間テーブルを指定すること**

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

####以上。