Single table inheritance opt-in

Nowadays, I feel like I don’t use Single Table Inheritance anymore. When I need this sort of paradigm, I reach for ActiveRecord::DelegatedType. Additionally, I’ve always found it annoying that I can’t easily use a column named type. For example, given a model called Food, I’d have to name it something like food_type, which feels pretty ugly. So lately, I’ve been doing:

class Food < ApplicationRecord
  self.inheritance_column = nil
end

Just so I can use type as the column name. What does everyone think about making STI opt-in, instead of being the default. For example:

class Food < ApplicationRecord
  has_single_table_inheritance
end

class Food < ApplicationRecord
  has_single_table_inheritance column: :variant
end

I think doing this would require a whole deprecation cycle.

Why not to put it into ApplicationRecord once per project and forget about it? Doesn’t it inherit properly?

You could go further and craft your own application template for that if you make a lot of projects and don’t want to put the line into every project manually.

Yeah, I can do that, but then everyone who joins the company/project has to find out we do this non-default thing. Just want to make it clear that I’m not complaining about the difficulty of the workaround. I’m just proposing we revisit the default given the alternative (delegated types) is opt-in. And, I’ve noticed less and less usage of STI these days due to its foot gun with autoload.

I always use “kind” rather than “type” in that situation

1 Like

I agree that ActiveRecord::DelegatedType can be a cleaner option when you need this kind of polymorphic structure without the constraints of Single Table Inheritance. Avoiding the reserved type column is also a nice benefit, especially when the domain model already has a natural field called type. It can make the schema and model design easier to understand.

I agree that it is weird that STI is automatically enabled once there is a type column and it would less surprising for it to be opt-in.

It feels like kind of an inconsistency, since the presence of a user_id column also does not automatically define belongs_to :user

This is especially annoying when dealing with tables not under your control or when defining ActiveRecord classes inside migrations (since data migration must often skip callbacks and other business logic defined in the original class), as the code will not work unless self.inheritance_column = nil is specified.

That said, I find it more pleasant to work with STI classes than DelegatedType, maybe I’m the only one.

But I guess at this point it’s too much of a breaking change to make it opt-in.