How to Use Multiple User Types (STI or Single Table Inheritance) with the Same Model in Ruby on Rails
Lately, I’ve been building a complex CRM for music teachers to manage students, invoicing, etc… It’s gotten a bit complicated, and I myself have learned a lot from this side project. One important thing I’ve learned is STI, or Single Table Inheritance. Basically, this lets you easily have sub models with their own intricacies, relationships, etc so you don’t clog up the main user class, but they all use the same table, and are easier to modify on their own.
I have admin.rb, student.rb, parent.rb, and teacher.rb files with classes to go with them…
I’ve built this all using Sorcery for the backend, but you can use devise, or whatever else floats your boat.
The first step is creating a “type” attribute on the users table. This is required by STI to know which type of user we’re dealing with. I’m going to assume you already have your user authentication system all setup.
rails g migration add_type_to_users type:string:index rake db:migrate
Next you’ll want to create a subclass. For this example we’re just going to use Student.
When we create this, we also need to make sure that when the “type” attribute is set it’s always titleized. You’ll get errors and have issues if for instance the user.type was set to “student” and not “Student”. Case matters in this case.
class Student < User # Here we setup the Student class. We could add the type method in here # however, that wouldn't be very dry of us, as we would need to add it to # each subclass. Instead we'll put that in user.rb. end
class User < ActiveRecord::Base #make sure to capitalize first letter of type, so it matches the Class. def type=(s) write_attribute(:type, s.to_s.titleize) end end
Now, just make sure each user has a type, or perhaps have some sort of fallback, or default type as well. Then whenever you query Student.all or Teacher.all you’ll be pulling data out of the users table, but only get back Student and Teachers.
Next you may want to checkout my article on: How to keep tables uncluttered by using profiles for each user type.
More good articles on Single Table Inheritance / STI:
- How (and When) to Use Single Table Inheritance in Rails
- Alex Reisner – Single Table Inheritance in Rails
- The Rail World – Single Table Inheritance with Rails
- Archon Systems – Rails Single Table Inheritance with Polymorphic Association