エンジニアになりweb開発に今月から携わるようになって初めてポリモーフィック関連付け、というのをやった。ちょっと最初理解に苦しんだのでアウトプットしておく。
ポリモーフィック関連付けとは?
一言でいうと、「一つのアソシエーションで複数のモデルと結びつく」ということ。ER図を用いて説明する。
まず、通常のアソシエーションでは1対1だろうが1対多だろうが一本の矢印が向かう先は1つである。
しかしポリモーフィック関連付けでは一本の矢印から複数のテーブルにアソシエーションが組まれる。
実装方法
ポリモーフィックの実装方法はそんなに難しくない。Railsガイドにも書いてある。
https://bit.ly/3v2wXOX
①マイグレーション実行時にpolymorphic: trueを付与
以下のようなマイグレーションファイルを作る
class CreateOrders < ActiveRecord::Migration[5.2]
def change
create_table :orders do |t|
t.date :order_date
t.references :orderable, polymorphic: true
t.timestamps
end
end
end
するとテーブルにimageable_id、imageable_type、という2つのカラムができる。
- orderable_id→外部キーにあたるカラム。ただし
foreign_key: true
はつけない。 - orderable_type→どのテーブルと紐付いているのか、の情報を持つ。アソシエーションを組んだモデルのクラス名が入る。
なお、手動で両カラムを設定する方法もある。
class CreateOrders < ActiveRecord::Migration[5.2]
def change
create_table :orders do |t|
t.date :order_date
t.bigint :orderable_id
t.string :orderable_type
t.timestamps
end
add_index :orders, [:orderable_type, :orderable_id]
end
end
マイグレーションファイルを設定したら
rails db:migrate
を実行しましょう。
②アソシエーションを組む
ポリモーフィックの場合、「~able」というのがそのままアソシエーション名になる(今回で言えばorderable)
class Order < ApplicationRecord
belongs_to :orderable, polymorphic: true
end
class Customer < ApplicationRecord
has_many :orders, as: :orderable
end
class Organization < ApplicationRecord
has_many :orders, as: :orderable
end
どんなメリットがあるの?
無駄な外部キーカラムができなくて済む
今回の例で言えば個人の顧客(Customer)、法人顧客(Organization)のどちらからでも購入されたらordersテーブルにデータを保存するようにしたい場合などに使える。通常個人の顧客が法人も兼ねる、というケースはまれなのでcustomer_id、organization_idと複数のカラムを作ってしまうと紐付いていないテーブルの外部キーがNULLになってしまう。これを避けることができる。
またCustomerとOrganizationで同じメソッドを定義しておけば呼び出しもラクになる。
class Order < ApplicationRecord
belongs_to :orderable, polymorphic: true
end
class Customer < ApplicationRecord
has_many :orders, as: :orderable
def get_name
customer_name
end
end
class Organization < ApplicationRecord
has_many :orders, as: :orderable
def get_name
organization_name
end
end
こんなメソッドは通常定義しないけど、同じ名前のget_nameっていうメソッドを用意しておけば
order = Order.new
order.orderable.get_name
でCustomer, Organizationどちらのメソッドでも呼び出せる。便利。