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.
精彩评论