メモ。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