多対多を表現する為の関連付け(has_many through、has_and_belongs_to_many)

f:id:ryoutaku_jo:20190506100546p:plain

【結論】

・テーブル間の多対多の関係を表す関連付けとして、has_many throughと、has_and_belongs_to_manyが存在する

・has_many throughは、中間テーブルのモデルに何らかの処理を記述したい場合に用いる

・has_and_belongs_to_manyは、中間テーブルのモデルに何らかの処理を行う必要が無い場合に用いる

【目次】

【本題】

多対多を表す関連付け

Railsのアソシエーションにおいて、多対多の関係を表す関連付けは二種類存在します。 今回は、それらの違いについては、解説します

共通点

いずれにも共通している点としては、「中間テーブル」の存在です。

一対一や一対多であれば、所属する側のテーブルに外部キーを持たせる事で、どのデータと紐付いているか判別が可能でした。 しかし、多対多だと、一つのデータに複数データが紐付いているという状況が双方で発生するので、外部キーを保存するカラムを増やしていかないと、どのデータと紐付いているか判別できません。

そこで登場するのが「中間テーブル」です。 中間テーブルは、多対多の関係性を持つテーブルの間に位置し、双方の外部キーを持つ事で、どのデータと紐付いているか特定が可能になります。

これにより、カラムを増やさずとも、レコードを増やすだけで、複数のデータの関連付けに対応出来る様になっています。

なおER図にすると、下記の様な内容です。

f:id:ryoutaku_jo:20190506094939p:plain

has_many through

has_many throughは、下記の様にモデルで関連付けを行います。

class Post < ApplicationRecord
  has_many :poststocks
  has_many :users, through: :poststocks
end

class PostStock < ApplicationRecord
  belongs_to :post
  belongs_to :user
end

class User < ApplicationRecord
  has_many :poststocks
  has_many :posts, through: :poststocks
end

中間テーブルに位置するモデルに、双方への所属を表す関連付けを記述するのが特徴です。

has_and_belongs_to_many

has_and_belongs_to_manyは、下記の様にモデルで関連付けを行います。

class Post < ApplicationRecord
  has_and_belongs_to_many :users
end

class User < ApplicationRecord
  has_and_belongs_to_many :posts
end

中間テーブルに位置するモデルには何も記述しないのが特徴です。

使い分け

has_and_belongs_to_manyは、中間テーブルのモデルが不要な為、中間テーブルのモデルに何らかの処理を記述する必要が無い場合に、最もシンプルで最適だと言えます。

逆にhas_many throughは、中間テーブルのモデルが必要ですが、中間テーブルを単なる関連付けの橋渡しでなく、ここに保存される情報も一つのデータとして扱いたい場合に採用される関連付けたと考えています。

例えば、「ユーザー」が「記事」に対して「いいね」する機能を実装する場合などです。 この場合、「いいね」の数も集計したりと、中間テーブルの情報自体にもデータとしての意味が出てくるので、has_many throughが最適だと言えます。

参考情報

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

《今日の学習進捗(3年以内に10000時間に向けて)》

学習開始からの期間 :149日
今日までの合計時間:1453h
一日あたりの平均学習時間:9.8h
今日までに到達すべき目標時間:1361h
目標との解離:92h
「10,000時間」まで、

残り・・・「8547時間!」