STIとポリモーフィック関連の整理

updated_at: 2023-04-30

概要

STIとポリモーフィック関連の理解が混同していたので改めて整理した記事。

STIとは

1つのテーブルを継承して複数のモデルを表現する形式。

具体例

carsテーブルとtrainsテーブルがvehiclesテーブルを継承すると仮定する。
クラス間の関係性は下図のようになる。


STIはテーブル一つで表現するため、DBに存在するテーブルはvehiclesテーブルのみ。

vehiclesテーブルのtypeカラムを使って、trains or carsの判別をする。

メリット

  • テーブルが増えない
  • Railsの場合だとSTIをサポートしているので実装容易性がある
  • サブクラスのレコードを取得するためにJOINする必要が無い


デメリット

  • カラム数が多くなる
  • 別のサブクラスで利用しなければnull値が増える
  • 特定のサブクラスのみを参照すべき他テーブルの外部キー制約が、誤ったサブクラスを参照することを防げない


参考

https://qiita.com/yebihara/items/9ecb838893ad99be0561

ポリモーフィック関連とは

複数のモデルから同じモデルを参照する際の関連付けの仕組み。
多態性という言葉より複数のモデルに対して共通のインターフェースを設けられる。
https://guides.rubyonrails.org/association_basics.html#polymorphic-associations

具体例

ProductモデルとEmployeeモデルはPictureモデルを参照すると仮定(railsガイドそのまま)

class Picture < ApplicationRecord
 belongs_to :imageable, polymorphic: true
end


class Employee < ApplicationRecord
 has_many :pictures, as: :imageable
end


class Product < ApplicationRecord
 has_many :pictures, as: :imageable
end


picturesテーブルには参照元の親テーブルを表すカラム(imageable_id / imageable_type)を持たせる。

class CreatePictures < ActiveRecord::Migration[7.0]
 def change
  create_table :pictures do |t|
   t.string :name
   t.bigint :imageable_id
   t.string :imageable_type
   t.timestamps
  end
  add_index :pictures, [:imageable_type, :imageable_id]
 end
end


@picture.imageableを介して親テーブルにアクセスできる。
@pictureがどの親に紐づいているかどうかの分岐が必要ない。(typeによる分岐等)

メリット

  • DRYに書ける
    • 中間テーブルを省いて相互に関連付けが可能
    • 共通インターフェースで関連付けが可能


デメリット

  • 外部キーを貼れないので参照整合性制約が担保されない


まとめ

ポリモーフィックとSTIの言語の意味を考えると自然とどちらか分かる。
まずは言語の意味をしっかり抑えようと思った。