[Rails] STI with namespace

下面是一個簡單STI(Single Table Inheritance) 的範例

class Animal < ActiveRecord::Base
end

class Dog < Animal
end

class Cat < Animal
end

dog = Dog.create
dog.type #=> "Dog"

當如果子model有namespace時

class Animal < ActiveRecord::Base
end
#models/animal/dog.rb

class Animal::Dog < Animal
end

class Animal::Cat < Animal
end

dog = Animal::Dog.create
dog.type #=> "Animal:Dog"

但如果想要的type是不包含namespace的話就需要override sti_name 這個method, demodulize 是把namespace拿掉,這個method想放在parent model裡也是可以

class Animal::Cat < Animal
    def self.sti_name
    self.name.demodulize
  end
end

另一個做法是orveride store_full_sti_class method

class Animal < ActiveRecord::Base
    def self.store_full_sti_class
    false
  end
end

這樣子type的問題是解決了,但是如果要做操作的話就會有問題會出現下面的error message

ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'Dog'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite Animal::Dog.inheritance_column to use another column for that information.

會出現這樣子的錯誤應該是因為他是照type name去找class,但因為已經沒有namespace了所以他找不到model
解決的方法是在parent model orveride find_sti_class method,這樣就可以順利操作了。

class Animal < ActiveRecord::Base
    def self.find_sti_class(type_name)
    type_name = self.name
    super
  end
end

Referance
Single Table Inheritance and 'type' value for namespaced classes

comments powered by Disqus