从ActiveRecord模型继承时防止STI

时间:2012-07-26 19:02:54

标签: ruby-on-rails ruby sti

在Rails 3.2.6上,我有一个继承自ActiveRecord :: Base的类:

class Section < ActiveRecord::Base
  ...
end

当我从这个类继承时,Rails会假设我想要STI:

class AnotherSection < Section
   ..Rails assumes I have a type field, etc...
end

我希望能够从Section类继承并使用子类作为普通的Ruby子类,而不使用Rails STI魔法。

在从ActiveRecord::Base模型中进行子类化时,有没有办法阻止STI?

3 个答案:

答案 0 :(得分:34)

您可以通过禁用模型的inheritance_column来实现此目的,如下所示:

class AnotherSection < Section
  # disable STI
  self.inheritance_column = :_type_disabled

end

答案 1 :(得分:10)

接受的答案肯定会有效,但推荐的(我敢说“正确”:)方式是设置<activity android:name=".MainActivity" android:theme="@style/AppTheme"/>

abstract_class

答案 2 :(得分:1)

在ActiveRecord上存储继承的唯一完全支持的策略是STI。但是,您可以自行承担模拟具体类表继承的风险。具有抽象超类的具体类表继承工作正常,如smathy所指出的那样。

但是......如果您想要的是使 AnotherSection 只是一个普通的类(不会在数据库中保留),您可以禁用鉴别器列(如Veraticus所建议的那样)。但是,如果您保存 AnotherSection ,它将与Section保持在同一个表中,您将无法区分它们。此外,如果您使用 AnotherSection 来查找 Section ,它将返回 AnotherSection ,从而打破原始实例化:

    #create a Section and saves it
    sect = Section.create()
    sect.save() 
    #retrieve the Section as a AnotherSection, breaking polymorphism... 
    sect = AnotherSection.find(sect.id)
    # another section is more than a section, it is inconsistent.

如果 AnotherSection 不打算保留,那么它是覆盖持久性操作的最安全的路径,例如save()和find():

    class AnotherSection < Section
       # disable STI, as pointed by Veraticus
       self.inheritance_column = :_type_disabled
       # disable save and finding
       def save(*args)
         #exception? do nothing?
       end
       def find(*args)
         #exception? do nothing?
       end
       def find_by(*args)
         #exception? do nothing?
       end
       # this does not stops here! there is first, last, and even a forty_two finder method! not to mention associations...
    end
简而言之,你可以做到这一点,但你应该这样做。风险很高。 您应该考虑另一个选项,例如使用MIXIN而不是继承。