Active Record の関連付け (アソシエーション) | Rails ガイド
関連付けのメリット
- Railsがテーブル間の関連を知ることで、必要な作業を勝手にやってくれる
- 例えば、顧客と注文が関連していたら、顧客の情報を消した時に、顧客に紐付いた注文を全部消してくれる(
dependent: :destroy
を定義した場合)
関連付けの種類
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
1対1
- belongs_to, has_one
- belongs_to : 従属
- 1人のUserに対して、Profileは1つ
belongs_to
側が相手のidを持つ(マイグレーション時に勝手に作ってくれる)- 今回ならば、
user_id
model
class User < ActiveRecord::Base has_one :profile # 主 end class Profile < ActiveRecord::Base belongs_to :user # 従 end
作ってみる
rails g model user name:string rails g model profile address:string user:belongs_to
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.timestamps null: false end end end class CreateProfiles < ActiveRecord::Migration def change create_table :profiles do |t| t.string :address t.belongs_to :user, index: true, foreign_key: true t.timestamps null: false end end end
sqlite> .schema users CREATE TABLE "users" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL); sqlite> .schema profiles CREATE TABLE "profiles" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar, "user_id" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL); CREATE INDEX "index_profiles_on_user_id" ON "profiles" ("user_id");
1対多
- belongs_to, has_many
- 1人のUserに対して、Orderは複数
class User < ActiveRecord::Base has_many :order # 主 end class Order < ActiveRecord::Base belongs_to :user # 従 end
has_mamy と has_one は、Rails上の制約でしか無い?
多対多
- through オプション を使う
- Appointment(予約)、Physician(医者)、Patient(患者)
- Physicianは、Appointmentsを経由して、Patientsに紐付いている
has_many :patients, through: :appointments
class Physician < ActiveRecord::Base has_many :appointments has_many :patients, through: :appointments end class Appointment < ActiveRecord::Base belongs_to :physician belongs_to :patient end class Patient < ActiveRecord::Base has_many :appointments has_many :physicians, through: :appointments end
through オプション を使った、ネストした関連のショートカット
class Document < ActiveRecord::Base has_many :sections has_many :paragraphs, through: :sections end class Section < ActiveRecord::Base belongs_to :document has_many :paragraphs end class Paragraph < ActiveRecord::Base belongs_to :section end
Document 1 -> * Section 1 -> * Paragraph
has_many :paragraphs, through: :sections
を書くことで、Documentは、Sectionを通して、Paragraphと、関連していることを定義- すると、
@document.paragraphs
が呼べるようになる
has_and_belongs_to_many
- has_mamy: through と同じ多対多だけど、modelを介在しない
- 〜_id だけを持つテーブルは使う
- そのテーブルはRails上は、modelを持たない
ポリモーフィック関連付け
- belongs_to の参照先を抽象化する
class Picture < ActiveRecord::Base belongs_to :imageable, polymorphic: true end class Employee < ActiveRecord::Base has_many :pictures, as: :imageable end class Product < ActiveRecord::Base has_many :pictures, as: :imageable end
この場合、Picture
は、belongs_to
を2個書く必要は無い
ポリモーフィック関連付け用のマイグレーション
rails g model picture name:string imageable:references
自己結合
- 自分で自分を関連付け
- 従業員(Employee)モデルで、マネージャーと部下を関連付けたい時など
class Employee < ActiveRecord::Base has_many :subordinates, class_name: "Employee", foreign_key: "manager_id" belongs_to :manager, class_name: "Employee" end
rails g model employee name:string manager:references