Enums as the default mapper/approach for SingleTableInheritance (STI)

Enum uses integers at the database level which gives them the advantage of being more performant in terms of query speed and index sizes as compared to storing strings. So, it handles integer <-> string mapping.

STI uses strings at the database and code level and then further map those strings to Classes. So, in general it does mapping like string <-> string <-> class.

What if we use enum as the default mapper for STI? integer <–enum–> string <–STI–> class. This gives all the performance and extra goodies (methods and scopes) of enum to STI as well.

I didn’t find any docs on this but the following implementation works out-of-the-box

class User
  enum type: { Teacher: 0, Student: 1 }
end

class Teacher < User; end
class Student < User; end

You can now do,

User.create(type: 'Student')    # <Student::0x00007fb...>
Student.create                  # <Student::0x00006tv...>
User.all(type: 'Student')       # Student array
Student.all                     # Student array

# Extra helper methods and scopes
user.Student?    # boolean
User.Student     # Student array

The capital letters in method names and scopes don’t look rubistic, but the following work will also solve this, https://github.com/rails/rails/pull/39677 https://github.com/rails/rails/pull/39673/files

Renaming classes would be as simple as renaming the class and updating the enum

- enum type: { Teacher: 0, Student: 1 }
+ enum type: { Professor: 0, Student: 1 }

So, is this supposed to work and can it become the default approach for implementing STI?

1 Like

Any updates on this approach or alternative solutions in Rails? Curious if your thoughts have evolved on it.