【Rails 6】Active Recordの関連付け機能(アソシエーション)について解説

# 1 対 多の関係モデルの作成

##### コマンド
`rails g model comment board:references name:string comment:text`

`comment` => 1 対 **多** に該当する作成するモデル名
`board:references` => **1** 対 多に該当するモデル名
(`:references`と記述することでboardモデルに紐付ける`board_idがcommentモデルに作成される。`)
`name:string comment:text` => 新しく作成するカラム名とデータ型


## 作成されたmigrateファイル
```ruby

class CreateComments < ActiveRecord::Migration[6.0]
  def change
    create_table :comments do |t|
      t.references :board, null: false, foreign_key: true
      t.string :name, null: false
      t.text :comment,null: false

      t.timestamps
    end
  end
end

```

`foreign_key: true` は外部キー制約を意味する。
boardsテーブルに存在しないidに対し新規でcommentテーブルのboard_idカラムを作成できない。
即ち、boardテーブルに紐付けられないものは作成できなくするためのもの。

**その他**
`null: false`は入力必須にするためのもの。


**テーブルの作成**
`rails db:migrate`

## board modelへアソシエーションを記述 
```board.rb
class Board < ApplicationRecord
has_many: comments
validates :name, presence: true, length: { maximum: 10 }
validates :title, presence: true, length: { maximum: 30 }
validates :body, presence: true, length: { maximum: 1000 }
end

```
`has_many: comments`
Boardsテーブルからcommentｓテーブルを見たときに, 1 対 多の関係になるため,

Boardモデルに記述するアソシエーションは`has_many: comments`となる。

## comment　modelへアソシエーションを記述


```comment.rb
class Comment < ApplicationRecord
  belongs_to :board
end
```
 `belongs_to :board` はモデル作成時に自動で記述される。
 `belongs_to :board`はcommentモデルから見たboardモデル。

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

中間テーブル`board_tag_relations`を用意して多　対　多のアソシエーションを実現する。

|  | 元テーブル | 中間テーブル | 元テーブル |
|:--|:--|:--|:--|
| テーブル名 | Boards | board_tag_relations | Tags |
| カラム | <font color="red">id</font> | id | <font color="red">id</font>  |
|  | name | <font color="red">board_id</font>  | name |
|  | title | <font color="red">tag_id</font>  |  |
|  | body |  |  |


#### Step1:Tagモデルを作成する
コマンド
`rails g model tag name:string`

#### Step2:board_tag_relationsモデル（中間テーブル）を作成する
コマンド
`rails g model board_tag_relations board:references tag:references`

関連付けれる両方の元テーブルに対してreferences（参照）をつけて関連付けをする。

#### Step3:モデルの関連付けの追記

作成されたモデルを修正する。

**中間テーブルはすでに関連付けをされているのでこのまま。**

```board_tag_relations.rb
class BoardTagRelation < ApplicationRecord
  belongs_to :board
  belongs_to :tag
end
```
**tagモデル**
tagモデルから見た中間テーブルは**多**の関係になるので,`has_many`で関連付け。
また関連先のboardsテーブルも指定し,**through:**（スルー）<font color="red">ここポイント</font> を指定した後に中間テーブルを指定する。

```tag.rb
class Tag < ApplicationRecord
    has_many :board_tag_relations
    has_many :boards, through: :board_tag_relations
end
```

### boardモデル

boardモデルから見た、中間テーブルは**多**の関係になるので,`has_many`で関連付け。
また関連先のtagsテーブルも指定し,**through:**（スルー）<font color="red">ここポイント</font> を指定した後に中間テーブルを指定する。


```board.rb
class Board < ApplicationRecord
has_many :comments
has_many :board_tag_relations
has_many :tags, through: :board_tag_relations


validates :name, presence: true, length: { maximum: 10 }
validates :title, presence: true, length: { maximum: 30 }
validates :body, presence: true, length: { maximum: 1000 }
end
```

# dependentオプション

**dependentオプションとは、モデルに関連されたデータが削除されたときに、その関連に紐付かれたデータも同時に削除する機能**

コード

**Boardモデル**

```board.rb 
class Board < ApplicationRecord
#多　対　多の関係のアソシエーション
has_many :comments, dependent: :delete_all  　#dependent: :delete_allで削除している
has_many :board_tag_relations, dependent: :delete_all　#dependent: :delete_allで削除している
has_many :tags, through: :board_tag_relations


validates :name, presence: true, length: { maximum: 10 }
validates :title, presence: true, length: { maximum: 30 }
validates :body, presence: true, length: { maximum: 1000 }
end

```
**tagモデル**

```tag.rb
class Tag < ApplicationRecord
    has_many :board_tag_relations :dependent: :delete_all #dependent: :delete_allで削除している
    has_many :boards, through: :board_tag_relations
end
```
#### <font color="red">注意点</font>
`dependent`オプションを使用するときは、controllerのdestroyアクションに使用するメソッドは`delete`メッソッドは使用できないため、替わりに`destroy`メソッドを使用する。

```controller.rb
def destroy
        @board.destroy #dependentオプションをモデルに設定している場合はdeleteメソッドではなく、destroyメソッドを使用する。
        redirect_to boards_path, flash: { notice: "「#{@board.title}」の掲示板を削除しました。"}
    end
```