娯楽開発

娯楽開発

開発は娯楽。遊び心で開発をすすめるブログ。

【初心者向け】アソシエーションって何?というあなたへ【rails】

webサービスを作っているとモデルがたくさん生成されてしんどくなってくるんですが、それらのアソシエーションをしたくて解説記事を探してもなかなかわかりづらくてよりしんどみが増してくる今日この頃です。

そんな迷える子羊な僕のために僕自身が僕自身の手で僕の解釈を解説してみました。そんな内容です。

今回の記事は下記サイトの内容を踏襲してます。

railsguides.jp

僕の記事は基本そうですが、参考サイト以上の情報は出てこないのでこれらのサイトを難なく理解できる方はそちらを読んだ方が早いと思います。

(書いてる僕自身rails初心者ですので間違っている箇所等あれば遠慮なくご指摘いただけると幸いです。)

アソシエーションとは

アソシエーション(association)を日本語にすると「「関連付け」だそうです。 railsでコードにするとだいたいこんな感じになります。

f:id:sado_tech:20180810084718p:plain

では関連付けとはどういうことかというと、簡単に言うと「こっちのモデルはあっちのモデルとこういう関係性にありますよ〜」という説明書きのことです。

これをしておくことでrailsのシステムがモデルの関係性を把握してくれて、モデル間のデータのやりとりなどをなんかこう、スムーズに行うことができたりします。

モデルってなんやねん

こんな感じです。

f:id:sado_tech:20180810220434p:plain

この場合だと黄色がモデル、青がインスタンスというように呼ばれます。

モデルは性質や特性、できることなどのインスタンスに共通する内容が書かれた説明書のようなイメージです。

一方インスタンスはモデルという説明書に沿った特徴・性質を持つ具体的なモノのことを指します。それぞれのインスタンスはモデルに沿った同一の特徴を持ちますが、インスタンスごとに異なった特徴も持っています。

この例だと「車」モデルの中に「プリウス」「タント」「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

具体例

f:id:sado_tech:20180810120345p:plain

先ほども登場した「車」モデルと「タイヤ」モデルのアソシエーションの例ですね。

「車」モデルのインスタンスであるプリウスは「タイヤ」モデルのインスタンスであるタイヤを必ず4つ所有します。

これはプリウスに限った話じゃなくて「車」モデルに属するインスタンスであればどんなものにでも当てはまることなので、「車」モデルのインスタンスは「タイヤ」モデルに対して常に「1対多」の関係が成り立つことになります。

つまり「車」モデルは「タイヤ」モデルに対してhas_manyの関係を持っていると言えます。

一方タイヤ1に注目して見るとどうでしょう。プリウスは複数のタイヤを持っていますが、タイヤ1が所有されている「車」モデルのインスタンスプリウスだけですね。タイヤ1がその他の「車」インスタンスに所有されることはまずありえません。

このように各「タイヤ」インスタンスから見ると、「タイヤ」モデルと「車」モデルの間には常に「1対1」の関係性が成り立つことになります。つまり「タイヤ」モデルは「車」モデルに対してbelongs_toの関係を持っていると言えます。

has_one

has_one

具体例

f:id:sado_tech:20180810222743p:plain

続いてhas_oneの例です。

これは前述のhas_manyが持つ相手方インスタンスが1つに限られる場合の話だと思ってください。

今回はマイナンバーを例に出しますが、マイナンバーは政府によって例外なく日本国民全員に1つずつ与えられますね。1人が複数のマイナンバーを持つことはありえません。常に1対1の関係性です。

ここでhas_onebelongs_toは同じ1対1に対して使うアソシエーションですが、その違いは「所有している」か「所属している(所有されている)」かです。今回の例では「人物」が「マイナンバー」を所有し、「マイナンバー」は「人物」に所有されています。ということで「人物」モデルから見た「マイナンバー」モデルとの関係性はhas_oneとなります。

この辺りは曖昧な部分も多いので、詳細について知りたい方は主キー(primary key)と外部キー(foreign key)などについて調べてみるといいかもしれません。

www.pc-master.jp

has_many :through と has_and_belongs_to_many

has_many :through, has_and_belongs_to_many

  • 中間モデルを経由することで、注目するインスタンスと相手となるインスタンスの間で多対多の関係性が構築されることを示す
  • 中間モデルとなる3つ目のモデルを必要とする

具体例

f:id:sado_tech:20180810120425p:plain

「1対1」、「1対多」ときたところで「多対多」です。上の図では学校などでの友人関係のつもりで例に出しています。深い意図はないので純粋な目で見てください。

少し複雑になりました。A男から見てF助は友達ですが、F助もまたA男以外にたくさんの友達を持ちます。つまりどのインスタンスから見ても相手方のインスタンスを複数所有しているわけですね。車とタイヤのように明確な所有と所属の関係が成立しないためhas_manybelongs_toでは表現できません。

このような場合にhas_many :throughhas_and_belongs_to_manyを用います。(図では例としてhas_many :throughを出していますがhas_and_belongs_to_manyでも代用可能です。)

この例だと一見して2つのモデルが直接関係を持ち合っているように見えますが、実際は以下の図のように2つのモデルを中継する3つ目のモデルが存在します。

f:id:sado_tech:20180810120452p:plain

このように中間モデルを使うことによって両サイドのモデルは中間モデルに対してhas_manyを、中間モデルは各モデルに対してbelongs_toを持つことになり、多対多の関係性をhas_manybelongs_toの関係に置き換えられるという仕組みなわけですね。

で、どっちを使えばいいの?

お察しの通り、基本的な働きは同じなhas_many :throughhas_and_belongs_to_manyです。どのような判断基準のもとどちらを使えばいいんでしょう?

参照元のサイトには以下のように書いてありましたので、参考にしてみてください。

どちらを使用するかについてですが、経験上、リレーションシップのモデルそれ自体を独立したエンティティとして扱いたい(両モデルの関係そのものについて処理を行いたい)のであれば、中間に結合モデルを使用するhas_many :throughリレーションシップを選ぶのが最もシンプルです。リレーションシップのモデルで何か特別なことをする必要がまったくないのであれば、結合モデルの不要なhas_and_belongs_to_manyリレーションシップを使用するのがシンプルです(ただし、こちらの場合は結合モデルが不要な代わりに、専用の結合テーブルを別途データベースに作成しておく必要がありますので、お忘れなきよう)。

Active Record の関連付け (アソシエーション) | Rails ガイド

has_one :through

has_one :through

  • 中間モデルを経由することで、注目するインスタンスと相手となるインスタンスの間で1対1の関係性が構築されることを示す
  • 中間モデルとなる3つ目のモデルを必要とする

具体例

f:id:sado_tech:20180810120542p:plain

こちらはhas_many :throughの1対1バージョンだと捉えていただけるとわかりやすいかなと。

正直これについては具体的な用途が思いつかなかったんですが、

  • モデル構造的には中間モデルを介して紐づけられるけど、参照する場合には直接的に(has_oneのように)参照したい

というような場合に使うことになるのかなぁと思っています。

何かいい例が見つかれば後日追記でもしようかと思います。

まとめ

今回はアソシエーションの種類を概念的な部分を中心にまとめてみました。なんとなくモデルのアソシエーションについて理解できたでしょうか。

いつか実際のコードなども使いながら具体的な用途も紹介できたらなーと思っているので気長に待っていていただけるとうれしいです。