[Rails] Active Recordの関連付け

## はじめに

Ruby on Rails における Active Record の関連付けは、データベース内のテーブル間の関係を簡単に表現する方法です。この記事では、Rails の主要な関連付けタイプについて解説します。

## なぜ関連付けを使うのか？

関連付けを使用する主な理由は以下の通りです：

1. コードをシンプルに保つ
2. データベースの操作を簡単にする
3. モデル間のつながりを分かりやすくする
4. 共通の操作を一貫して行える

## Rails の主要な関連付けタイプ

Rails では以下の 6 種類の関連付けがあります。それぞれを日常生活の例を使って説明していきます。

### 1. `belongs_to`（〜に属する）

`belongs_to` は、「このモデルは他のモデルに属している」という関係を表します。

例：生徒は学級に属している

```ruby
class Student < ApplicationRecord
  belongs_to :classroom
end

class Classroom < ApplicationRecord
  has_many :students
end
```

ER 図：

```mermaid
erDiagram
    CLASSROOM ||--o{ STUDENT : has
    CLASSROOM {
        integer id
        string name
    }
    STUDENT {
        integer id
        string name
        integer classroom_id
    }
```

解説：
- 1人の生徒は1つの学級にのみ属します。
- `classroom_id` は `Student` モデルに存在し、どの学級に属しているかを示します。

### 2. `has_one`（1つを持つ）

`has_one` は、「このモデルは他のモデルを1つだけ持っている」という関係を表します。

例：ユーザーは1つのプロフィールを持つ

```ruby
class User < ApplicationRecord
  has_one :profile
end

class Profile < ApplicationRecord
  belongs_to :user
end
```

ER 図：

```mermaid
erDiagram
    USER ||--|| PROFILE : has
    USER {
        integer id
        string name
    }
    PROFILE {
        integer id
        integer user_id
        string bio
    }
```

解説：
- 1人のユーザーは1つのプロフィールのみを持ちます。
- `user_id` は `Profile` モデルに存在し、どのユーザーのプロフィールかを示します。

### 3. `has_many`（たくさん持つ）

`has_many` は、「このモデルは他のモデルをたくさん持っている」という関係を表します。

例：先生は複数の生徒を持つ

```ruby
class Teacher < ApplicationRecord
  has_many :students
end

class Student < ApplicationRecord
  belongs_to :teacher
end
```

ER 図：

```mermaid
erDiagram
    TEACHER ||--o{ STUDENT : has
    TEACHER {
        integer id
        string name
    }
    STUDENT {
        integer id
        string name
        integer teacher_id
    }
```

解説：
- 1人の先生は複数の生徒を持つことができます。
- `teacher_id` は `Student` モデルに存在し、どの先生に属しているかを示します。

### 4. `has_many :through`（〜を通じてたくさん持つ）

`has_many :through` は、中間テーブルを介して「このモデルは他のモデルをたくさん持っている」という関係を表します。

例：医者は患者をたくさん持ち、患者は医者をたくさん持つ。予約が中間テーブルとなる

```ruby
class Doctor < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :doctor
  belongs_to :patient
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :doctors, through: :appointments
end
```

ER 図：

```mermaid
erDiagram
    DOCTOR ||--o{ APPOINTMENT : has
    PATIENT ||--o{ APPOINTMENT : has
    DOCTOR {
        integer id
        string name
    }
    APPOINTMENT {
        integer id
        integer doctor_id
        integer patient_id
        date appointment_date
    }
    PATIENT {
        integer id
        string name
    }
```

解説：
- 1人の医者は複数の患者を持ち、1人の患者は複数の医者にかかることができます。
- `Appointment`（予約）が中間テーブルとなり、医者と患者の関係を橋渡しします。

### 5. `has_one :through`（〜を通じて1つ持つ）

`has_one :through` は、中間テーブルを介して「このモデルは他のモデルを1つ持っている」という関係を表します。

例：従業員は1つの会社PCを持ち、その会社PCは1つの保証書を持つ

```ruby
class Employee < ApplicationRecord
  has_one :company_computer
  has_one :warranty, through: :company_computer
end

class CompanyComputer < ApplicationRecord
  belongs_to :employee
  has_one :warranty
end

class Warranty < ApplicationRecord
  belongs_to :company_computer
end
```

ER 図：

```mermaid
erDiagram
    EMPLOYEE ||--|| COMPANY_COMPUTER : has
    COMPANY_COMPUTER ||--|| WARRANTY : has
    EMPLOYEE {
        integer id
        string name
    }
    COMPANY_COMPUTER {
        integer id
        integer employee_id
        string serial_number
    }
    WARRANTY {
        integer id
        integer company_computer_id
        date expiration_date
    }
```

解説：
- 1人の従業員は1台の会社PCを持ち、その会社PCは1つの保証書を持ちます。
- 従業員は会社PCを通じて間接的に保証書を持つことになります。

### 6. `has_and_belongs_to_many`（お互いにたくさん持つ）

`has_and_belongs_to_many` は、中間テーブルを使わずに直接「このモデルと他のモデルがお互いにたくさんある」という関係を表します。

例：本は複数のジャンルに属し、ジャンルは複数の本を持つ

```ruby
class Book < ApplicationRecord
  has_and_belongs_to_many :genres
end

class Genre < ApplicationRecord
  has_and_belongs_to_many :books
end
```

ER 図：

```mermaid
erDiagram
    BOOK }o--o{ GENRE : has_and_belongs_to_many
    BOOK {
        integer id
        string title
    }
    GENRE {
        integer id
        string name
    }
    BOOKS_GENRES {
        integer book_id
        integer genre_id
    }
```

解説：
- 1冊の本は複数のジャンルに属することができ、1つのジャンルには複数の本が含まれます。
- `books_genres` という中間テーブルが自動的に作成され、本とジャンルの関係を管理します。

## まとめ

Rails の関連付けを使うことで、データベース内のテーブル間の関係を簡単に表現できます。それぞれの関連付けタイプは異なる状況で使われ、モデル間の関係をコードで表現するのに役立ちます。

## 参考
https://railsguides.jp/association_basics.html