Rails single table inheritance (STI)
Inheritance is used when entities are of a similar kind but can be categorised further. Child classes represent is_a relationship with parent classes. For example, with parent classes Person and child classes Student, Teacher, and Librarian. We can read it like student is_a person, teacher is_a person etc.
When Inheritance is implemented in Ruby, child classes can inherit parent classes and start using its behaviour. In Rails, models are tightly coupled with databases through ActiveRecord, which requires maintaining the class hierarchy in the database as well as using type columns.
database tables are created along with the model using the rails generate model command. To create the same class hierarchy mentioned above, we need to create models of person, student, teacher, and librarian but only one table having name people in the database.
Create the first model person with the command:
rails g model person first_name:string last_name:string type:string email:string
This will create the Person model and migration file like below:
class Person < ApplicationRecord
end
class CreatePeople < ActiveRecord::Migration[7.0]
def change
create_table :people do |t|
t.string :first_name
t.string :last_name
t.string :type
t.string :email
t.timestamps
end
end
end
Now to create sub-classes student, teacher, and librarian, without database tables run below commands.
rails g model teacher --skip-migration
rails g model librarian --skip-migration
rails g model student --skip-migration
class Teacher < ApplicationRecord
end
class Librarian < ApplicationRecord
end
class Student < ApplicationRecord
end
Now the next step is to update class definitions to extend the Person class like the below:
class Teacher < Person
end
class Librarian < Person
end
class Student < Person
end
We are ready to use these classes and create database records. Create the below records from the rails console.
student = Student.create(first_name: 'Kavita', last_name: 'Jadhav', email: 'kavita@mail.com')
teacher = Teacher.create(first_name: 'Jyoti', last_name: 'Jadhav', email: 'kavita@mail.com')
librarian = Librarian.create(first_name: 'Ravi', last_name: 'Jadhav', email: 'kavita@mail.com')
These will create records in the people table with their respective types. When querying person records with the orm all method, it will list all three records, but then the all method is run with individual child class, it will return list single record of the respective class.
Person.all
Teacher.all
Librarian.all
Student.all
Happy coding!