Rails

多対多の関連付けについてのまとめ

RailsでDBを構築する際によく使用される「多対多の関連付け」について。

has_many :through

とある病院の診療予約管理システムを考える。

患者(patient.rb)と医師(Physician.rb)は多対多の関係性にある。1人の患者は複数の医師にかかっているだろうし、1人の医師もまた複数の患者を診察している。

このとき、患者と医師は予約情報(Appointment.rb)を介して関連付けするとスムーズになる。

patient.rb
class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end
physician.rb
class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end
appointment.rb
class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end

多対多の関連付けは、上記のようなソースコードで記述される。

先述したように、ここで特徴的なのはPatientモデルとPhysicianモデルは、直接的な関連付けがなされていないという点。

スクリーンショット 2017-11-03 3.26.31.png
(RailsGuideより抜粋:https://railsguides.jp/association_basics.html#has-many-through%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91)

ここでappointmentsテーブルは、physiciansテーブルとpatientsテーブルの間に入っているため、中間テーブルと呼ばれます。

また、Appointmentモデルのように、2つのモデルの中立ちを行うモデルを結合モデルと呼びます。

SNSアプリケーションにおける多対多

多対多関連付けは2つの独立したモデルを、第3のモデルを介して関連付けます。

Railsチュートリアルなどで作成するサンプルアプリケーションでは、twitterのようにユーザーをフォローする機能を実装する。

フォローするユーザーAとフォローされるユーザーBは、どちらも同じUserモデル。

また、ユーザーAはユーザーBをフォローしているものの、ユーザーBはユーザーAをフォローしていない可能性がある。そのため、図のように新たにRelationshipモデルを作成し、フォロー情報を管理する必要がある。

image.png

こうすることにより、1人のユーザーAが複数のユーザーを、relationshipテーブルを介してフォローしているという状態を作り出すことが出来る。

user.rb
class User < ActiveRecord::Base
  has_many :microposts, dependent: :destroy
  has_many :relationships, foreign_key: "follower_id", dependent: :destroy
  has_many :followed_users, through: :relationships, source: :followed

 #( 中略 )

end