RailsでDBを構築する際によく使用される「多対多の関連付け」について。
has_many :through
とある病院の診療予約管理システムを考える。
患者(patient.rb)と医師(Physician.rb)は多対多の関係性にある。1人の患者は複数の医師にかかっているだろうし、1人の医師もまた複数の患者を診察している。
このとき、患者と医師は予約情報(Appointment.rb)を介して関連付けするとスムーズになる。
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
多対多の関連付けは、上記のようなソースコードで記述される。
先述したように、ここで特徴的なのはPatientモデルとPhysicianモデルは、直接的な関連付けがなされていないという点。
(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モデルを作成し、フォロー情報を管理する必要がある。
こうすることにより、1人のユーザーAが複数のユーザーを、relationshipテーブルを介してフォローしているという状態を作り出すことが出来る。
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