4

我在我正在开发的 Rails 应用程序中遇到了这种相当奇怪的行为。

我在继承层次结构中有多种类型的 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

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

class Post < ActiveRecord::Base
    has_many :feed_entries
    self.abstract_class = true
end

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

...然后在以前保存的对象上调用 FeedEntry#post 关联会返回 Post 类型的对象。这似乎相当倒退(鉴于抽象类声明明确表示不应实例化该类),我想不出这种行为的原因。

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

4

2 回答 2

7

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

听起来您想要做的是self.abstract_class = true通过使用 initialize 方法删除和模拟抽象类,以便仅在该类不是type时才允许实例化Post

例如:

class Post < ActiveRecord::Base    
  def initialize 
    raise "Post cannot be instantiated directly" if self.class == Post   
  end
end

这样,您就可以维护您的 STI 模型并拥有一个伪抽象基类。希望这可以帮助!

于 2011-04-04T12:45:41.457 回答
0

通过覆盖abstract_class?超类中的方法,abstract_class?将为所有子类返回 true,而不仅仅是超类。

相反,我认为你应该使用:

class Post < ActiveRecord::Base
  self.abstract_class = true
end

我没有尝试过,但我相信这会解决你的问题。

于 2011-04-03T13:51:21.433 回答