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?