为什么当它的超类是抽象的时,rails不尊重与STI相关的belongs_to关联对象的类型?

mis*_*tim 4 activerecord abstract-class ruby-on-rails belongs-to sti

我在我正在研究的rails应用程序中遇到了这个相当奇怪的行为.

我在继承heirarchy中有多种类型的Post,以及Post has_many FeedEntries.

class Post < ActiveRecord::Base
    has_many :feed_entries
end

class Post::BlogPost < Post; end
class Post::Discussion < Post; end
class Post::Article < Post; end

class FeedEntry < ActiveRecord::Base
    belongs_to :post
end
Run Code Online (Sandbox Code Playgroud)

现在,当我像以前一样设置所有内容时,在保存的对象上调用FeedEntry#post总是返回正确(子类)类型的对象,正如我所期望的那样.但是,如果我使Post摘要(它确实应该是 - 在这个模型中永远不应该实例化超类):

class Post < ActiveRecord::Base
    has_many :feed_entries
    self.abstract_class = true
end
Run Code Online (Sandbox Code Playgroud)

_(注意:我编辑了这段代码片段以考虑下面的tomafro建议,因为设置self.abstract_class似乎比覆盖self.abstract_class更惯用?但是,相同的行为仍然存在.)

...然后在先前保存的对象上调用FeedEntry#post关联返回Post类型的对象.这看起来相当倒退(假设抽象类声明明确表示该类不应该被实例化),我想不出这种行为的原因.

那么,有什么理由我没有得到,或者它是一个错误,还是其他什么?

Mik*_*keH 7

通过self.abstract_class = true在基础对象中指定,您实际上是禁用STI.设置 self.abstract_class = true实际告诉ActiveRecord 没有与该类关联的数据库表,因此您继承的类将各自拥有自己的数据库表.

听起来你想要做的是删除self.abstract_class = true和模拟一个抽象类,使用initialize方法只允许实例化,如果类不是类型Post.

例如:

class Post < ActiveRecord::Base    
  def initialize 
    raise "Post cannot be instantiated directly" if self.class == Post   
  end
end
Run Code Online (Sandbox Code Playgroud)

这样,您可以维护STI模型并具有伪抽象基类.希望这可以帮助!