Reputation: 2123
On Rails 3.2.6, I have a class that inherits from ActiveRecord::Base:
class Section < ActiveRecord::Base
...
end
When I inherit from this class, Rails will assume I want STI:
class AnotherSection < Section
..Rails assumes I have a type field, etc...
end
I want to be able to inherit from the Section
class and use the subclass as a normal Ruby subclass, without the Rails STI magic.
Is there a way to prevent STI when subclassing from an ActiveRecord::Base
model?
Upvotes: 36
Views: 14245
Reputation: 402
The only fully supported strategy to store inheritance on ActiveRecord is STI. You can, however, simulate concrete class-table inheritance at your own risk. The concrete class-table inheritance with abstract superclass works fine, as pointed by smathy.
BUT ... If what you want is to make AnotherSection just an ordinary class (that will not be persisted at the database), you could disable the discriminator column (as suggested by Veraticus). However, if you save the AnotherSection it will be persisted in the same table as Section, and you will not be able to tell them apart. Also, if you use AnotherSection to find a Section, it will return an AnotherSection, breaking the original instantiation:
#create a Section and saves it
sect = Section.create()
sect.save()
#retrieve the Section as a AnotherSection, breaking polymorphism...
sect = AnotherSection.find(sect.id)
# another section is more than a section, it is inconsistent.
If AnotherSection is not intended to be persisted, the safest path it to override the persistence operations, such as save() and find():
class AnotherSection < Section
# disable STI, as pointed by Veraticus
self.inheritance_column = :_type_disabled
# disable save and finding
def save(*args)
#exception? do nothing?
end
def find(*args)
#exception? do nothing?
end
def find_by(*args)
#exception? do nothing?
end
# this does not stops here! there is first, last, and even a forty_two finder method! not to mention associations...
end
in a nutshell, you can do this, but you SHOULDN´T. The risk is high. You should consider another option, such as using MIXIN instead of inheritance.
Upvotes: 1
Reputation: 27971
The accepted answer will definitely work, but the recommended (dare I say "proper" :) way is to set abstract_class
:
class Section < ActiveRecord::Base
self.abstract_class = true
end
Upvotes: 13
Reputation: 16074
You can achieve this by disabling the inheritance_column
for the model, like so:
class AnotherSection < Section
# disable STI
self.inheritance_column = :_type_disabled
end
Upvotes: 55