Ruby on Railsの勉強を進めていく中で、データモデルの関連付けについて、なぜ行うのか、どういうときにどういう関連付けを行うのか、ということがいまいちスッキリしないまま勉強を進めてしまっていたのですが、先日Rails Guideを読んでいてスッキリしたので、備忘録として書いてみようと思います。
自分もまだ勉強始めてそんなに経ってないので、間違ったこと言ってたら指摘お願いします。
以下は、rails guideの内容を自分なりにまとめたものなので、rials guideを読んだ方が早いかもしれませんが、興味あったら読んでみてください。
1.なぜモデルの関連付けが必要なのか
Railsでデータベースからデータを呼び出すとき、モデルクラスに属するメソッドを使って@user.nameみたいな感じで呼び出すと思います。
ユーザーモデルに属するnameという値を呼び出すときは@user.nameでいいんですけど、仮に各ユーザーが、投稿(Micropost)モデルに属する投稿(posts)データを所持しているとします。(twitterでいうと、ユーザはそれぞれ自分のツイートを所持している、といった感じです)
このとき、異なるモデルに属する(投稿)postsを呼び出したくても、モデル同士の関連付けがされていないと、@user.postsのような形で呼び出すことはできません。
この場合、Micropost.where(user_id: @user.id)のように指定する必要があります。
これを簡略化して、「この投稿はこのユーザーに属します。このユーザーはこの投稿を所持しています」とrailsに明示的に示してあげることで、@user.posts などといった書き方ができるようになります。
このように、関係性を宣言することでより簡潔にコードを記述することができるようになります。
2. 1対1の関係(例:結婚)
例えば、婚姻関係を管理する政府系機関のデータベースにおいて、男モデルと女モデルがあった場合、1人の男に対して、結婚相手の女性は1人であると考えられますから、この場合は1対1の関係と言えるでしょう。
このとき、has_one、belongs_to を用いますが、どっちにhas_one、どっちにbelongs_toを書くのでしょうか。
これは意味をそのまま考えればよくて、has_oneの主語となるモデルが、目的語を所持している、という状態を表します。そしてbelongs_toの主語、つまり所持されている側にはforeign_keyとして、参照する外部キーを指定して、関連付けをします。
結婚関係の場合、どちらがどちらを所持するかという判断は微妙なところですが、今回は「男が女を所持している」ということにしましょう。
その場合、男 has_one 女 女 belongs_to 男 foreign_key 男_id となるわけですね。
別にプログラミングの上では逆でももちろん構わないわけで、
女 has_one 男 男 belongs_to 女 foreign_key 女_id でも問題ないです。
ただ、それぞれにおいて、データの呼び出し方が変わってきます。男が女を所持している場合には、男を呼び出すときは「@男」でよく、女は「@男.女」みたいな形で呼び出せます。
逆の場合、男は「@女.男」、女は「@女」で呼び出せます。
(もちろん関連付けと関係なく単体で呼び出したいときは、@男、@女、でインスタンスを呼び出せば良いです。)
どっちがいいか、というのはどういうデータの管理をしたいか、ということによります。
例えば家ごとのデータを管理したい場合、家主は男性であることの方が多いでしょうから、男に対して色々なデータを紐づける方が理にかなっている感じはしますね。
ここはプログラム的にどうっていうわけではなくて、その時々の要件に応じてつかいわけましょう、という感じですね。
では次
3. 1対多の関係
これはさくっと終わらせます。実際これは1対1の関係と考え方は変わらないし、どっちがどっちを所持しているかというのも明白です。
「1の方が多を所持している」と考えるわけですね。
1 has_many 多
多 belongs_to 1 です
1人が沢山のものを所持している、と考える方が、沢山のものが1人を所持している、と考えるよりは自然でしょう。
4. 多対多の関係(例:男女)
例として、男女の交際関係を考えてみましょう。
1人の男性が多数の女性と付き合っていることもあれば、1人の女性が多数の男性と付き合っていることもあるでしょう。
この場合、モデルの作成方法としては2つ存在しますが、違いは「関係性をエンティティとして扱うかどうか」です。
つまり、男女の関係性を実体のあるものとして解釈し、何らかの操作や情報を加えたりしたいかどうか、ということです。男女の関係性であれば、関係があるかないか、だけでなくて、「セフレ」や「結婚を前提」「遊び」「友達以上恋人未満」など、関係性に対して情報を付加したい場合には、「関係モデル」を作る必要があります。
【関係性をエンティティとして扱う場合】
「男モデル」、「女モデル」に加えて、「関係モデル」を作成します。
先ほども説明したように、関係性を表すテーブルを作成し、ある男とある女の関係性を実体 あるものとして扱うわけです。
この場合
男モデルの中には
has_many :女 through:関係
has_many:関係
と記述し、女モデルの中には
has_many :男 through:関係
has_many :関係
そして関係モデルには
belongs_to :男
belongs_to :女
と記述します。
この場合、男と女はどっちがどっちに属する、という関係ではなく「関係モデルを通して、多数の女(男)を所持しています。」と書くわけですね。
そして「関係は男と女に属している(所持されている)わけですね。」
このように「関係モデル」を新しく作ったことで、関係を実体あるものとして扱い、先ほども言ったように、「親密さ」などの情報を付加できるようになりました。
【関係をエンティティとして扱わない場合】
男モデルには
has_many_and_belongs_to :女
女モデルには
has_many_and_belongs_to :男
と記述します。
この場合、男と女は互いに所持し、所持される対等な関係にあり、非常に簡潔に記述されていることがわかるかと思います。
関係を実態として扱わない場合には、「関係モデル」を新しく作る必要はありませんが、「関係の有無のみを記録するテーブル」は作る必要があります。
関係の有無だけを記録したい場合は、こちらの方がシンプルですね。
以上、なぜモデルの関連付けを行うのか、ということに始まり、「1対1、1対多、多対多」の関係について書いてみました。