Wednesday, March 21, 2012

ActiveRecord Inheritance without STI (Single Table Inheritance)

Update: The Rails community rocks! Less than 24 hours after I wrote this post and posted this issue to github, I had a solution from markmcspadden and a commit into docrails to help others understand how to get around this problem. The short answer:

self.abstract_class = true

I am writing this blog post in frustration to inform folks googling for how to do ActiveRecord without STI to give up now--it doesn't work and probably never will.

Common sense would suggest that you could bypass the single table inheritance mechanism with something like:
class SuperClass < ActiveRecord::Base
end
class Child < SuperClass
self.table_name = 'the_table_i_really_want'
end
However, this doesn't work. An invocation like `Child.first` results in SQL like:
SELECT super_classes.* FROM super_classes LIMIT 1
and an error like:
ActiveRecord::StatementInvalid: Could not find table 'super_classes'
I.e. it doesn't honor the fact that self.table_name was overridden in the child.
I've tried many other variations of this to make this work, with no luck.

Thought STI is awesome, its REALLY frustrating when you want to use inheritance without it.
I know, I know, "you should use mixins instead" is the common reply. However, this seems strange that I can't use inheritance without STI--inheritance is one of the fundamental programming constructs of an object oriented language, please, don't take it away from me and give me STI instead. Please, give me both!

For example, it would be amazing if I could do something like:

class SuperClass < ActiveRecord::Base
self.hell_with_single_table_inheritance = true
end
And have:
Child.create

work as expected.

Maybe there is a way to do this, and I don't know about it--if so, please comment here and let me know and share with the Rails community!