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

房东的猫 提交于 2019-12-10 16:03:17

问题


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?


回答1:


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!




回答2:


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.



来源:https://stackoverflow.com/questions/5529916/why-does-rails-not-respect-the-type-of-a-belongs-to-associated-object-with-sti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!