Ruby on Railsで多対多のテーブル設計を動かしながら理解してみる

## 記事の内容
- 多対多のアソシエーションとは
- 中間テーブルとは
- Railsで多対多のアソシエーションを実装
- 実際にコンソールで確認してみる




**間違っている箇所などありましたらご指摘ください。**


## 多対多のアソシエーションとは

多対多のアソシエーションとは、ある2つのテーブルの関係性が「複数 対 複数」であるということです。
例えば、Qiitaにも実装されている、ブログ記事にタグ付けする機能を実装したいという想定で、１つのブログ記事には複数のタグを関連付けることができる。そして、１つのタグを複数のブログ記事に関連付けることができるという機能を実装します。


- ブログ記事
    - 複数のタグを設定できる
- タグ
    - 複数のブログ記事に設定できる



## 中間テーブルを作成して2つのテーブルを関連付ける

多対多のアソシエーションを実装するために、今回は中間テーブルを使った方法の解説です。
「個人的に中間テーブルと言われてもピンとこない…」という感じだったので画像を交えてみます。


![](https://paper-attachments.dropbox.com/s_86A980E0DF18E6DE002F825782B36E11629395B9E34A21DDCB58682BFEB275FD_1568376504714_.jpg)


articlesテーブルとtagsテーブルを繋ぐ中間テーブルでそれぞれのidを管理することで多対多のアソシエーションを実装します。

もしarticlesテーブルのレコードが削除された時、関連付いている中間テーブルのレコードも削除されてほしい




## Railsで多対多のアソシエーションを実装

それぞれのモデルを生成します。

```
$ rails g model Article title:string body:string

$ rails g model Tag name:string

$ rails g model ArticleTagRelation article:references tag:references
```

`:references`と指定することでそれぞれのモデルと関連付けされた状態で生成されます。

```app/models/article.rb
class Article < ApplicationRecord
  has_many :article_tag_relations, dependent: :destroy
  has_many :tags, through: :article_tag_relations
end
```
```app/models/tag.rb
class Tag < ApplicationRecord
  has_many :article_tag_relations, dependent: :destroy
  has_many :articles, through: :article_tag_relations
end
```

- 中間テーブル

```app/models/article_tag_relation.rb
class ArticleTagRelation < ApplicationRecord
  belongs_to :article
  belongs_to :tag
end
```
`has_many`で関連付けする場合は、モデル名は複数形で指定して、belongs_toで関連付けする場合は、モデル名を単数形で指定します。

`:dependent`はarticleやtagレコードが削除された場合の動作を指定します。
`:destroy`を指定することで関連付けされた中間テーブルのレコードが削除されます。

**※`:destroy`で削除した場合、削除するレコード数分SQLが実行される**



## Rails consoleで実際に確認してみる
### 手順
- `rails new`して実装を確認
- 上のモデル生成コマンドで3つのモデルを生成
- `rails console`でデータを作成
- 関連付けができているかの確認
- 削除した時、関連レコードも削除できているか確認
- DBのテーブルの確認はDB Browser for SQLiteを使う

<a href="https://qiita.com/MZ1TB0ZSoVfeX9L/items/eba47bbf47d7d64de9a9" target="_blank">**DB Browser for SQLiteの使用方法**</a>


テスト用アプリケーション作成


```
$ rails new test_app
```

モデル作成

```
$ rails g model Article title:string body:string
$ rails g model Tag name:string
$ rails g model ArticleTagRelation article:references tag:references
```

**※rails db:migrateを実行**


モデルファイルに関連付け

```article.rb
class Article < ApplicationRecord
  has_many :article_tag_relations, dependent: :destroy
  has_many :tags, through: :article_tag_relations
end
```
```tag.rb
class Tag < ApplicationRecord
  has_many :article_tag_relations, dependent: :destroy
  has_many :articles, through: :article_tag_relations
end
```
```article_tag_relation.rb
class ArticleTagRelation < Application
  belongs_to :article
  belongs_to :tag
end
```

Railsコンソールでデータを作成

``` 
$ rails c
> Tag.create(name: 'Rails')
> Article.create(title: 'タイトル', body: 'テスト', tag_ids: [1])
````

DB Browser for SQLiteでarticle_tag_relationテーブルを確認


Articleモデルのレコードを削除してarticle_tag_relation.rbのレコードも一緒に削除されているか確認

```
> Article.first.destroy
```

削除されていれば多対多の関連付けが完了しています。


## 参考
- <a href="https://railsguides.jp/association_basics.html#has-many-through%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91" target="_blank"> has_many :through関連付け : Railsガイド</a>
- <a href="https://railsguides.jp/association_basics.html#has-many%E3%81%AE%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3" target="_blank">has_manyのオプション : Railsガイド</a>
- <a href="https://qiita.com/kamelo151515/items/0fa7fb15a1d2c1e44db2" target="_blank">delete, delete_all, destroy, destroy_allについて : Qiita</a>