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

published_at: 2022-12-11

概要

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

STIとは

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

具体例

carsテーブルとtrainsテーブルがvehiclesテーブルを継承すると仮定する。

クラス間の関係性は下図のようになる。

STI Models

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

STI Table

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ガイドそのまま)

1class Picture < ApplicationRecord 2 belongs_to :imageable, polymorphic: true 3end 4 5class Employee < ApplicationRecord 6 has_many :pictures, as: :imageable 7end 8 9class Product < ApplicationRecord 10 has_many :pictures, as: :imageable 11end

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

1class CreatePictures < ActiveRecord::Migration[7.0] 2 def change 3 create_table :pictures do |t| 4 t.string :name 5 t.bigint :imageable_id 6 t.string :imageable_type 7 t.timestamps 8 end 9 add_index :pictures, [:imageable_type, :imageable_id] 10 end 11end

@picture.imageableを介して親テーブルにアクセスできる。

@pictureがどの親に紐づいているかどうかの分岐が必要ない。(typeによる分岐等)

メリット

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

デメリット

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

まとめ

ポリモーフィックとSTIの言語の意味を考えると自然とどちらか分かる。

言語の意味をしっかり抑えようと思った。