【初心者向け】アソシエーションって何?というあなたへ【rails】
webサービスを作っているとモデルがたくさん生成されてしんどくなってくるんですが、それらのアソシエーションをしたくて解説記事を探してもなかなかわかりづらくてよりしんどみが増してくる今日この頃です。
そんな迷える子羊な僕のために僕自身が僕自身の手で僕の解釈を解説してみました。そんな内容です。
今回の記事は下記サイトの内容を踏襲してます。
僕の記事は基本そうですが、参考サイト以上の情報は出てこないのでこれらのサイトを難なく理解できる方はそちらを読んだ方が早いと思います。
(書いてる僕自身rails初心者ですので間違っている箇所等あれば遠慮なくご指摘いただけると幸いです。)
アソシエーションとは
アソシエーション(association)を日本語にすると「「関連付け」だそうです。 railsでコードにするとだいたいこんな感じになります。
では関連付けとはどういうことかというと、簡単に言うと「こっちのモデルはあっちのモデルとこういう関係性にありますよ〜」という説明書きのことです。
これをしておくことでrailsのシステムがモデルの関係性を把握してくれて、モデル間のデータのやりとりなどをなんかこう、スムーズに行うことができたりします。
モデルってなんやねん
こんな感じです。
この場合だと黄色がモデル、青がインスタンスというように呼ばれます。
モデルは性質や特性、できることなどのインスタンスに共通する内容が書かれた説明書のようなイメージです。
一方インスタンスはモデルという説明書に沿った特徴・性質を持つ具体的なモノのことを指します。それぞれのインスタンスはモデルに沿った同一の特徴を持ちますが、インスタンスごとに異なった特徴も持っています。
この例だと「車」モデルの中に「プリウス」「タント」「NOTE」といったインスタンスが含まれてますね。いずれのインスタンスも「車」モデルに属してはいますがいずれもメーカーや搭載シート数など固有の特徴を持っています。
例えば
それではここにもし新たに「タイヤ」モデルができた場合、「車」モデルと「タイヤ」モデルの間にはどういう関係性があるんでしょう?
そんな時にモデルで事前に関係性を示しておくのがアソシエーションです。
このように、railsを使ったwebサービスではこういったモデルをたくさん用意して、それらの関連付け(アソシエーション)をする工程が必要となります。今回はその工程でのお話というわけですね。
アソシエーションの種類
さて本題です。
railsでサポートされているRelationは以下の6種類です。
belongs_to
has_many
has_one
has_many :through
has_and_belongs_to_many
has_one :through
早速解説していきましょう。
belongs_to と has_many
has_many
belongs_to
具体例
先ほども登場した「車」モデルと「タイヤ」モデルのアソシエーションの例ですね。
「車」モデルのインスタンスであるプリウスは「タイヤ」モデルのインスタンスであるタイヤを必ず4つ所有します。
これはプリウスに限った話じゃなくて「車」モデルに属するインスタンスであればどんなものにでも当てはまることなので、「車」モデルのインスタンスは「タイヤ」モデルに対して常に「1対多」の関係が成り立つことになります。
つまり「車」モデルは「タイヤ」モデルに対してhas_many
の関係を持っていると言えます。
一方タイヤ1に注目して見るとどうでしょう。プリウスは複数のタイヤを持っていますが、タイヤ1が所有されている「車」モデルのインスタンスはプリウスだけですね。タイヤ1がその他の「車」インスタンスに所有されることはまずありえません。
このように各「タイヤ」インスタンスから見ると、「タイヤ」モデルと「車」モデルの間には常に「1対1」の関係性が成り立つことになります。つまり「タイヤ」モデルは「車」モデルに対してbelongs_to
の関係を持っていると言えます。
has_one
has_one
具体例
続いてhas_one
の例です。
これは前述のhas_many
が持つ相手方インスタンスが1つに限られる場合の話だと思ってください。
今回はマイナンバーを例に出しますが、マイナンバーは政府によって例外なく日本国民全員に1つずつ与えられますね。1人が複数のマイナンバーを持つことはありえません。常に1対1の関係性です。
ここでhas_one
とbelongs_to
は同じ1対1に対して使うアソシエーションですが、その違いは「所有している」か「所属している(所有されている)」かです。今回の例では「人物」が「マイナンバー」を所有し、「マイナンバー」は「人物」に所有されています。ということで「人物」モデルから見た「マイナンバー」モデルとの関係性はhas_one
となります。
この辺りは曖昧な部分も多いので、詳細について知りたい方は主キー(primary key)と外部キー(foreign key)などについて調べてみるといいかもしれません。
has_many :through と has_and_belongs_to_many
has_many :through, has_and_belongs_to_many
具体例
「1対1」、「1対多」ときたところで「多対多」です。上の図では学校などでの友人関係のつもりで例に出しています。深い意図はないので純粋な目で見てください。
少し複雑になりました。A男から見てF助は友達ですが、F助もまたA男以外にたくさんの友達を持ちます。つまりどのインスタンスから見ても相手方のインスタンスを複数所有しているわけですね。車とタイヤのように明確な所有と所属の関係が成立しないためhas_many
と belongs_to
では表現できません。
このような場合にhas_many :through
やhas_and_belongs_to_many
を用います。(図では例としてhas_many :through
を出していますがhas_and_belongs_to_many
でも代用可能です。)
この例だと一見して2つのモデルが直接関係を持ち合っているように見えますが、実際は以下の図のように2つのモデルを中継する3つ目のモデルが存在します。
このように中間モデルを使うことによって両サイドのモデルは中間モデルに対してhas_many
を、中間モデルは各モデルに対してbelongs_to
を持つことになり、多対多の関係性をhas_many
とbelongs_to
の関係に置き換えられるという仕組みなわけですね。
で、どっちを使えばいいの?
お察しの通り、基本的な働きは同じなhas_many :through
とhas_and_belongs_to_many
です。どのような判断基準のもとどちらを使えばいいんでしょう?
参照元のサイトには以下のように書いてありましたので、参考にしてみてください。
どちらを使用するかについてですが、経験上、リレーションシップのモデルそれ自体を独立したエンティティとして扱いたい(両モデルの関係そのものについて処理を行いたい)のであれば、中間に結合モデルを使用するhas_many :throughリレーションシップを選ぶのが最もシンプルです。リレーションシップのモデルで何か特別なことをする必要がまったくないのであれば、結合モデルの不要なhas_and_belongs_to_manyリレーションシップを使用するのがシンプルです(ただし、こちらの場合は結合モデルが不要な代わりに、専用の結合テーブルを別途データベースに作成しておく必要がありますので、お忘れなきよう)。
Active Record の関連付け (アソシエーション) | Rails ガイド
has_one :through
has_one :through
具体例
こちらはhas_many :through
の1対1バージョンだと捉えていただけるとわかりやすいかなと。
正直これについては具体的な用途が思いつかなかったんですが、
- モデル構造的には中間モデルを介して紐づけられるけど、参照する場合には直接的に(
has_one
のように)参照したい
というような場合に使うことになるのかなぁと思っています。
何かいい例が見つかれば後日追記でもしようかと思います。
まとめ
今回はアソシエーションの種類を概念的な部分を中心にまとめてみました。なんとなくモデルのアソシエーションについて理解できたでしょうか。
いつか実際のコードなども使いながら具体的な用途も紹介できたらなーと思っているので気長に待っていていただけるとうれしいです。