Railsの関連付けのオプションについて

## 概要
前回のモデルの関連付けの種類の記事の続きです。
モデルの関連付けの際に使用できるオプションについてアウトプットしていきたいと思います。
[前回の記事](https://qiita.com/soicchi/items/306206fb3eed1d377c6a)

## 環境
ruby: '3.0.1'
rails: '6.1.4'

## 前提
今回説明するにあたって下記のモデルを想定しています。

usersテーブル

|id|name|
|:--:|:--:|
|1|user1|
|2|user2|

departmentsテーブル（所属部署を管理するテーブル）

|id|name|
|:--:|:--:|
|1|営業部|
|2|開発部|

Assignmentsテーブル（所属部署を管理するテーブル）

|id|user_id|department_id|
|:--:|:--:|:--:|
|1|1|1|
|2|1|2|
|3|2|1|

## オプションの種類
### 1. through
`through`は__多対多__の関係のモデル同士を関連付ける際に、そのモデル同士の中間に設置するモデルを経由させる際に使用します。

#### 使い方
_*models/user.rb*_

```ruby
class User < ApplicationRecord
  has_many :assignments # まずは中間のモデルとの関連付け
  has_many :departments, through: :assignments # 多対多のモデルを関連付ける際にthroughオプションに中間のモデルを記載
end
```

_*models/assignment.rb*_

```ruby
class Assignment < ApplicationRecord
  belongs_to :user # userと従属の関係
  belongs_to :department # departmentと従属の関係
end
```

_*models/department.rb*_

```ruby
class Department < ApplicationRecord
  has_many :assignments
  has_many :users, through: :assignments
end
```

関連付けを行うことで下記のように直接departmentsやusersにアクセスできます。

```ruby
user = User.find(1)
user.departments #=> user1が所属する部署一覧を取得

department = Department.find(1)
department.users #=> その部署に所属しているユーザーを取得
```

#### <備考> 中間テーブルの必要性
中間テーブルがなぜ必要かを説明します。
結論から言うと、テーブル設計の冗長性をなくすためです。
たとえば、一人のユーザーが営業部と開発部の両方に所属、また営業部には複数のユーザーが所属していると仮定します。
このような場合、テーブルを管理する際に下記のように所属部署が増えるたびにカラムが増えることになります。

usersテーブル

|id|name|department_id_1|department_id_2|・・・|
|:--:|:--:|:--:|:--:|:--:|
|1|user1|1|2|・・・|

departmentsテーブルも同様に所属ユーザーが増えればカラムが増えてしまいます。
これを解決するために中間テーブルを設置します。

Assignmentsテーブル（所属部署を管理するテーブル）

|id|user_id|department_id|
|:--:|:--:|:--:|
|1|1|1|
|2|1|2|
|3|2|1|

ユーザーの所属部署を中間テーブル（Assignmentsテーブル）で管理することで
usersテーブルやdepartmentsテーブルでは先程のような冗長性はなくなります。

### 2. foreign_key
`foreign_key`は外部キーを変更したい場合に使用するオプションです。
通常関連付けを行うと外部キーは__'関連付けモデル名'+_id__になります。
これを別の名称に変更することができます。

#### 使い方
_*models/user.rb*_

```ruby
class User < ApplicationRecord
  has_many :assignments, foreign_key: 'user_number'
end
```
上記のように記載することで参照元の外部キーを`user_id`から`user_nubmer`変更することができます。
フォロー、フォロワー機能の実装のように同じテーブル同士を中間テーブルを介して関連付けを行う際に使用したりします。

### 3. class_name
`class_name`は関連付けを行う関連名を変更する際に使用するオプションです。
関連名を変更してしまうと、どのモデルと関連付けされているのか判断できなくなるため
関連付け先のモデル名を記載します。

#### 使い方
_*models/department.rb*_ （他のモデルの設定は）

```ruby
class Department < Application
  has_many :assignments
  has_many :employees, through: :assignments, class_name: 'User' # class_name追加
end
```

_*models/user.rb*_

```ruby
class User < ApplicationRecord
  has_many :assignments
  has_many :departments, through :assignments
end
```

_*models/assignment.rb*_

```ruby
class Assignment < ApplicationRecord
  belongs_to :user
  belongs_to :department
end
```
これにより下記のように参照の仕方を変えることができます。

```ruby
department = Department.find(1)
# class_name追加前
# department.users
# class_name追加後
department.employees # 部署に所属してるユーザーが取得できる
```

### 4. dependent
`dependent`はテーブルのデータが削除された際に関連付けられているデータも削除するときに使用します。

#### 使い方
_*models/user.rb*_

```ruby
class User < ApplicationRecord
  has_many :assignments, dependent: :destroy
end
```
上記のように設定するとユーザーが削除された際に紐付いているassignmentsテーブルのデータも削除されるようになります。

## まとめ
以上がよく使われるオプションになります。
他にもオプションはたくさんありますので詳しく確認したい場合は下記参考文献を参照ください。

## 参考文献
https://railsguides.jp/association_basics.html#%E8%87%AA%E5%B7%B1%E7%B5%90%E5%90%88

https://pikawaka.com/rails/association#%E4%B8%AD%E9%96%93%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%A8through%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3