読者です 読者をやめる 読者になる 読者になる

ここにタイトルが入ります

デザイン&プログラミングのことも書くし、それ以外のことも書く。

【Rails】ActiveRecord:単一テーブル継承(sti)とポリモーフィック関連を未だにぱっと思い出せないのでまとめ。

Rails

ActiveRecordで単一テーブル継承(STI:Single Table Inheritance)とポリモーフィック関連という2つの便利なモデルの持ち方?関係性?があるのですが、恥ずかしながらいつも混同してしまいます…

多分頭の中では両方とも「似たモデルをまとめる」みたいなぼんやりした認識してるので混ざってしまっているようで…


すごい今更ですが
ちょっと自分なりにまとめてみようと思います。


単一テーブル継承(STI:Single Table Inheritance)

同じような機能(メソッド)を持つActiveRecordモデルクラスが2つ存在するので、
継承を使って実装しようとした場合。

例として
「Information」モデルを継承した「Warning」クラスと「Notice」クラスを作成するとします。
(例としておかしかったらごめんなさい…)
単純に実装すると、各モデルに対しDBのテーブルが作成されるのですが、
STIではInformationテーブルのみを使用して実装することができます。


f:id:blog_711fumi:20121104164051j:plain


モデルの定義はこんな感じ。

class Information < ActiveRecord::Base
  …
end

class Warning < Information
  …
end

class Notice < Information
  …
end

で、例えばWarningオブジェクトをsaveすると、Informationテーブルにtype:Warningとして保存されます。
Noticeならtype:Noticeに。

それぞれのモデルからデータへの操作を行った場合、適合するTypeのデータのみを操作対象とします。
両方をまとめて扱いたい場合(WarningもNoticeも関係なく取得したいとか)は、
Informationモデルから操作すればOKだと思います多分。


当然ひとつのテーブルを使っていますので、片方にしか無い項目(カラム)もテーブルに含まなければなりません。
例えばWarningとNoticeの持つ項目があまりにも違う場合、カラム数すげー増えます。
あまりないと思いますけど。


〜参考にさせていただきました!〜
Railsで単一テーブル継承(Single Table Inheritance) - 京の路


ポリモーフィック関連(polymorphic)


ココ見りゃいいって話ではありますが…

〜参考にさせていただきました!〜
Active Record Associations — Ruby on Rails Guides
ruby/rails/RailsGuidesをゆっくり和訳してみたよ/Active Record Associations - 株式会社ウサギィwiki


例えばアプリケーションなんかで、CompanyモデルとUserモデルを持っていたとします。
両方とも画像モデルクラス(会社の写真、ユーザーのプロフィール写真)と関連しているのですが、
持っている項目が全く同じなので一つのモデルとして管理したい場合、ポリモーフィック関連で実装できます。


f:id:blog_711fumi:20121104164730j:plain


モデルの定義はこんな感じ。

class Image < ActiveRecord::Base
  belongs_to :imageable, :polymorphic => true
end

class Company < ActiveRecord::Base
  has_many :images, :as => :imageable
end

class User < ActiveRecord::Base
  has_many :images, :as => :imageable
end


こうすることでTypeによって紐付く親が判別されるので、UserやCompanyモデルから自身に関係するImageが取得できます。
親モデルが新たに増えたとしても、has_manyの関連を定義してやるだけでImageモデルが利用できるわけですね。


とか書きましたがすごく丁寧に解説されている記事が…

〜すごく参考にさせていただきました!〜
2010-06-19 - 篳篥日記
おすすめ!


ただ疑問なのが、imageのエイリアス?としてimageableと付けること…
なんかしっくりこない。
ポリモーフィック関連の例を見てると大体〜ableってつけてるみたいなんですよね。。

…確かに親IDを格納するカラムがImage_idだとおかしい気もしますが、
imageable_idとかimageable_typeとかもピンとこないような…


まとめてみて

STIはデータに対する同じ操作を持つモデルを継承でまとめ、
その同じ操作を持つモデルのデータをひとつのテーブルに押し込める。

ポリモーフィック関連は親子関係が同じようなやつをまとめ、
紐付く子データを親に関係なくひとつのテーブルに押し込める。

…明確に分けようとして言葉にしてみましたが
やっぱり意味分かんないですね説明できてないですね…
実装方法は難しいとこないのに…


なんというか
両方typeを利用して、複数のモデルのデータをひとつのテーブルに入れてるという点が
私が両者を混同してしまう原因だということはわかりました(*_*)