はじめに
こんにちは!
DMM WEBCAMP mentor Advent Calendar 2023 10日目 を担当します
@A22Dです!
初めての記事執筆となりますが、今回、Railsの「アソシエーション」に焦点を当て、その基本をわかりやすく説明したいと思います。
初心者の方でも「なるほど!」と思っていただけるよう心掛けますので、最後までお付き合いください!
概要
初心者の方へ、Railsの「アソシエーション」をわかりやすく解説します。
アソシエーションとは、モデル間の関連性を定義する強力な機能です。この記事では、例としてbook.user.name
やbook.user.introduction
を用いて、投稿された本の作者の名前やプロフィール画像の取得方法を紹介します。
前提環境
- Ruby 3.1.2
- Rails 6.1.7
目次
1:Nの関係について
初学者向けに1:Nの関係を理解しやすくするため、この記事では「親」と「子」という表現を使って説明します。
user.rbのアソシエーション
has_many :books, dependent: :destroy
- こちらはUserモデル(親)がたくさんのBookモデル(子)を持っているという関係性を示しています。
-
dependent: :destroy
は本を投稿したユーザーが消えた時、消えたユーザーが投稿した本もまとめて消すよー!っていうようなオプションです。
dependent: :destroy について
dependent: :destroy
はRailsのアソシエーションにおけるオプションの一つです。これを設定することで、あるモデル(例: User
モデル)が削除されたとき、関連付けられているモデルのデータ(例: User
が持っているBook
)も一緒に削除されるようになります。
例えば、user.rb
に以下のような関連付けがある場合、
has_many :books, dependent: :destroy
このUserが削除されると、そのUserに関連付けられている全てのBookも自動的に削除されます。これによりデータの整合性を保つことができます。
book.rbのアソシエーション
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
の情報を参照できるのです。
外部キーが存在しないと、、
-
外部キーが存在しないと、親の情報を持たない子供は、この子は一体誰の子供なのか、となってしまいますよね。そのため、子供は必ず外部キー(親の情報)を持っていなければならないということになります。
-
外部キーが存在していない場合、必ず存在しなければならないという系統のエラー(
〜must exist
)が発生する可能性があります。
アソシエーションのイメージ: 子供とお母さんの関係
-
book.user.name
の動作は、子供がお母さんに名前を尋ねる概念に似ています。
- 子供(book)はお母さん(user)を知っています。
- 子供がお母さんの名前(name)を知りたい時、直接お母さんに尋ねます。
- お母さんはその答え(名前)を子供に教えます。
こんな形で親子関係を結んでいるから子供がお母さんの名前を知ることができるように本も投稿者の名前を知ることができます。(bookとuserがアソシエーションを結んでいることがポイント!)
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 | スズキ | 運動が趣味です |
答えと解説
コントローラの@bookの中身
@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
は、「料理が趣味です」という内容を表示します。
おわりに
いかがでしたでしょうか。
今回の記事では、Railsのアソシエーション、特にモデル間の関連性を「親子関係」というアナロジーを用いて解説しました。book.user.name
のようなコードの背後にある仕組みを、より直感的に理解してもらうことを目指しました。🧐
初心者の方々がRailsのアソシエーションについて「なるほど!」と感じてもらえる内容としてまとめ上げましたが、まだまだ深掘りできる部分は多いです。今後の学習の中で、この記事が一つの足がかりとなれば幸いです。🎉
最後までお読みいただき、心から感謝いたします。🙇
明日からもAdvent Calendarはまだまだ続くので他の記事も読んで貰えると感無量です!!😭一緒に学んでいきましょう!!💪🔥🔥