【Rails】初心者様向けアソシエーション解説 book.user編

# はじめに
こんにちは！
<font color="red">**DMM WEBCAMP mentor Advent Calendar 2023**</font> :christmas_tree: **10日目** を担当します 
@A22Dです！
初めての記事執筆となりますが、今回、Railsの「アソシエーション」に焦点を当て、その基本をわかりやすく説明したいと思います。
初心者の方でも「なるほど！」と思っていただけるよう心掛けますので、最後までお付き合いください！

# 概要
初心者の方へ、Railsの「アソシエーション」をわかりやすく解説します。
アソシエーションとは、モデル間の関連性を定義する強力な機能です。この記事では、例として`book.user.name`や`book.user.introduction`を用いて、投稿された本の作者の名前やプロフィール画像の取得方法を紹介します。

# 前提環境

- Ruby 3.1.2
- Rails 6.1.7

# 目次
1. [1:Nの関係について](#1nの関係について)
    - [user.rbのアソシエーション](#userrbのアソシエーション)
    - [book.rbのアソシエーション](#bookrbのアソシエーション)
2. [`book.user`について](#bookuserについて)
    - [`book.user.name`の日本語訳](#bookusernameの日本語訳)
    - [なぜこのような参照が可能か？](#なぜこのような参照が可能か)
3. [アソシエーションのイメージ: 子供とお母さんの関係](#アソシエーションのイメージ-子供とお母さんの関係)
4. [book.user.nameの解析](#bookusernameの解析)
5. [まとめ](#まとめ)
6. [おまけ](#おまけ)
7. [おわりに](#おわりに)


# 1:Nの関係について
初学者向けに1:Nの関係を理解しやすくするため、この記事では「親」と「子」という表現を使って説明します。

### user.rbのアソシエーション

```ruby
has_many :books, dependent: :destroy
```
- こちらはUserモデル（親）がたくさんのBookモデル（子）を持っているという関係性を示しています。
- `dependent: :destroy`は本を投稿したユーザーが消えた時、消えたユーザーが投稿した本もまとめて消すよー！っていうようなオプションです。
 <details>
  <summary>dependent: :destroy について</summary>

  `dependent: :destroy`はRailsのアソシエーションにおけるオプションの一つです。これを設定することで、あるモデル（例: `User`モデル）が削除されたとき、関連付けられているモデルのデータ（例: `User`が持っている`Book`）も一緒に削除されるようになります。

  例えば、`user.rb`に以下のような関連付けがある場合、
```ruby  
has_many :books, dependent: :destroy
```
このUserが削除されると、そのUserに関連付けられている全てのBookも自動的に削除されます。これによりデータの整合性を保つことができます。
</details>

### book.rbのアソシエーション
```ruby
belongs_to :user
```
- こちらはBookモデル（子）がUserモデル（親）に属しているという関係性を示しています。
# `book.user`について

今回は`book.user.name`を通じて、`Book`モデルから`User`モデルのレコードを参照している理由について深く掘り下げます。

### `book.user.name`の日本語訳
初めに、`book.user.name`を日本語に訳すと「本、人、名前」となります。このままでは意味が伝わりにくいですね。  
しかし、もう少し考えて訳すと「本を投稿した人の名前」という意味になります。この表現ならば理解しやすいですね。

### なぜこのような参照が可能か？

では、`book.user.name`を使って、なぜ「本を投稿した人の名前」を参照できるのかを詳しく見ていきましょう。

- **親子関係の識別**: `Book`モデル（子）は投稿者のIDを持っており、これを使って`User`モデル（親）を識別できます。
  
- **外部キーの役割**: この関係性は、子供が自分の親の情報を知っているようなものです。具体的には、`user_id`を外部キーとして持っている`book`は、関連する`user`の情報を参照できるのです。

<details>
  <summary><font color="red">外部キーが存在しないと、、</font></summary> 
  
- 外部キーが存在しないと、親の情報を持たない子供は、この子は一体誰の子供なのか、となってしまいますよね。そのため、<font color="red">**子供は必ず外部キー（親の情報）を持っていなければならない**</font>ということになります。

- 外部キーが存在していない場合、必ず存在しなければならないという系統のエラー(`〜must exist`)が発生する可能性があります。
</details>

# アソシエーションのイメージ: 子供とお母さんの関係

- `book.user.name`の動作は、子供がお母さんに名前を尋ねる概念に似ています。
1. 子供（book）はお母さん（user）を知っています。
2. 子供がお母さんの名前（name）を知りたい時、直接お母さんに尋ねます。
3. お母さんはその答え（名前）を子供に教えます。

**こんな形で親子関係を結んでいるから子供がお母さんの名前を知ることができるように本も投稿者の名前を知ることができます。<font color="red">(bookとuserがアソシエーションを結んでいることがポイント！)</font>**

### **book.user.nameではこのような動きを、アソシエーションを通じてコードで再現しているのです。**
# book.user.nameの解析
今回は以下のテーブルから桃太郎を投稿した人の名前をどのように拾ってくるのかを表を使って表します。
### Bookテーブル
| id |   title   |       body        | user_id |
|:--:|:---------:|:-----------------:|:-------:|
|  1 | 桃太郎    | 桃太郎の物語です |    1    |
|  2 | 浦島太郎   | 浦島太郎の物語です |    1  |
|  3 | 一寸法師   | 一寸法師の物語です |    2   |
|  4 | かぐや姫   | かぐや姫の物語です |    3  |
### Userテーブル
| id |  name  |   introduction   |
|:--:|:------:|:----------------:|
|  1 | サトウ  | 読書が趣味です  |
|  2 | ヤマダ | 料理が趣味です   |
|  3 | スズキ | 運動が趣味です   |



### book
まず、bookは「桃太郎」のレコードを参照しています。


| id | title |       body        |user_id |
|:--:|:-----:|:-----------------:|:-------:|
|  1 | 桃太郎| 桃太郎の物語です| 1 |

### book.user
book.userは、簡単に言えば「この本を投稿したユーザーは誰？」と問いかけるコードです。
- 例えば、ある本が「サトウ」というユーザーによって投稿された場合、book.userを使うことでその「サトウ」さんの情報にアクセスすることができます。
- このbookに関連づけられた`user_id`は1です。そのため、`User`テーブルから`id`が1のレコードを参照します。

| id | name  | introduction    |
|:--:|:-----:|:---------------:|
|  1 | サトウ | 読書が趣味です |

### book. user. name

そして、このユーザーレコードから`name`カラムの値、つまり「サトウ」を取得します。

### 結論
`book.user.name`を実行すると、「桃太郎」を投稿したユーザーの名前、すなわち「サトウ」という結果が得られます。

# まとめ
Railsのアソシエーションは、モデル間の関係性を表現するキーです。親子関係のアナロジーを用いることで、book.user.nameのようなコードがどのように動作するかをイメージしやすくしました。簡単に言えば、子モデルが親モデルの情報を引き出すように、アソシエーションを使えば関連するモデルのデータにアクセスできます。この記事を通じて、アソシエーションの基本を理解していただければ幸いです。

# おまけ
/book/3の詳細ページで`@book.user.introduction`には何が入るのか一緒に考えてみましょう。
URL /book/3 は、IDが3のBookモデルの詳細ページを示しています。
### Bookテーブル
| id |   title   |       body        | user_id |
|:--:|:---------:|:-----------------:|:-------:|
|  1 | 桃太郎    | 桃太郎の物語です |    1    |
|  2 | 浦島太郎   | 浦島太郎の物語です |    1  |
|  3 | 一寸法師   | 一寸法師の物語です |    2   |
|  4 | かぐや姫   | かぐや姫の物語です |    3  |
### Userテーブル
| id |  name  |   introduction   |
|:--:|:------:|:----------------:|
|  1 | サトウ  | 読書が趣味です |
|  2 | ヤマダ | 料理が趣味です   |
|  3 | スズキ | 運動が趣味です   |


 <details>
  <summary>答えと解説</summary>

### コントローラの＠bookの中身

```ruby
@book = Book.find(params[:id])
```
このparams[:id]は3を意味します。そのため、IDが3のBookのレコードを@bookに代入します。
| id | title   | body              | user_id |
|----|:-------:|:----------------:|:-----:|
| 3  | 一寸法師 | 一寸法師の物語です | 2       |

### Viewファイルでの@book.userの動作

@bookの`user_id`は2です。この`user_id`をもとに関連するUserのレコードを取得します
| id | name  | introduction      |
|----|-------|-------------------|
| 2  | ヤマダ | 料理が趣味です     |

### @book.user.introductionの動作
ヤマダさんの`introduction`は「料理が趣味です」となります。
### 答え
結果として、`@book.user.introduction`は、「料理が趣味です」という内容を表示します。
 </details>

# おわりに
いかがでしたでしょうか。
今回の記事では、Railsのアソシエーション、特にモデル間の関連性を「親子関係」というアナロジーを用いて解説しました。`book.user.name`のようなコードの背後にある仕組みを、より直感的に理解してもらうことを目指しました。🧐
初心者の方々がRailsのアソシエーションについて「なるほど！」と感じてもらえる内容としてまとめ上げましたが、まだまだ深掘りできる部分は多いです。今後の学習の中で、この記事が一つの足がかりとなれば幸いです。🎉
最後までお読みいただき、心から感謝いたします。🙇
明日からもAdvent Calendarはまだまだ続くので他の記事も読んで貰えると感無量です！！😭一緒に学んでいきましょう！！💪🔥🔥