メモ。STI (Single Table Inheritance) を使ってこんな構造を作りたいとする。
class Task < ActiveRecord::Base
end
class AbstractTask < Task
end
class ConcreteTask < Task
end
STI のデフォルト挙動では type
カラムの値にクラス名が入る。AbstractTask の場合には AbstractTask
、ConcreteTask の場合には ConcreteTask
となる。
が、tasks
テーブルを見ているわけで、Task であることはわかっているし、それぞれ abstract
、concrete
ぐらいにしたい。というただのこだわり。
こうすればできるようだ。
class Task < ActiveRecord::Base
end
class AbstractTask < Task
class << self
def find_sti_class(type_name)
type_name = self.name
super
end
def sti_name
"abstract"
end
end
end
class ConcreteTask < Task
class << self
def find_sti_class(type_name)
type_name = self.name
super
end
def sti_name
"concrete"
end
end
end
訂正。親クラスで定義しないと、Task.first
のようにインスタンスを作った場合に、適切に AbstractTask
、ConcreteTask
に変身してくれなかった。こんなかんじになった。
class Task < ActiveRecord::Base
class << self
def find_sti_class(type)
class_name = "#{type.camelize}Task"
super(class_name)
end
def sti_name
@sti_name ||= self.name == 'ConcreteTask' ? 'concrete' : 'abstract'
end
end
end
class AbstractTask < Task
end
class ConcreteTask < Task
end