32

在 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 魔法。

从模型子类化时有没有办法防止 STI ActiveRecord::Base

4

3 回答 3

47

您可以通过禁用inheritance_column模型来实现这一点,如下所示:

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

end
于 2012-07-26T19:10:39.313 回答
10

接受的答案肯定会起作用,但推荐的(我敢说“正确”:)方法是设置abstract_class

class Section < ActiveRecord::Base
  self.abstract_class = true
end
于 2015-06-17T23:55:00.610 回答
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 而不是继承。

于 2017-01-21T17:17:14.800 回答