开发者

Why does rails not respect the type of a belongs_to associated object with STI, when its superclass is abstract?

I've come across this rather odd bit of behaviour in a rails application I'm working on.

I have multiple types of Post in an inheritance heirarchy, and a 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

Now, when I have everything set up as before, calling FeedEntry#post on a saved object always returns an object of the correct (subclass) type, as I would expect. However, if I make Post abstract (which it really should be - the superclass should never be instantiated in this model):

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

_(note: I edited this code snippet to take into account tomafro's suggestion below, as setting self.abstract_class seems more idiomatic than overriding self.abstract_class?. However, the same behaviour still persists.)

...then calling the FeedEntry#post association on a previously saved object returns an object of type Post. This seems rather backwards (given that the abstract class declaration denotes specifically that that class should not be instantiated), and I can't think of a reason for this behaviour.

So, is there some reason for this I'm not getting, or is it a bug, or something else?


By specifying self.abstract_class = true in the base object, you are essentially disabling STI. Setting self.abstract_class = true actually tells ActiveRecord that there is not a database table associated with that class so your inherited classes will each have their own database table.

It sounds like what you want to do is remove self.abstract_class = true and simulate an abstract class by using the initialize method to only permit instantiation if the class is not of type Post.

For example:

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

This way, you maintain your STI model and also have a pseudo-abstract base class. Hope this helps!


By overriding the abstract_class? method in the superclass, abstract_class? will return true for all subclasses, not just the superclass.

Instead I think you should use:

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

I've not tried it, but I believe this will fix your issue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜