- Read Tutorial
- Watch Guide Video
In this guide, we are going to create an admin user using a tool called single table inheritance (STI).
Let's now talk a little about STI before we use it to create an admin user. If you open our schema.rb
file, you'll see a table called users
with a number of attributes. Now, if we want to create an admin user, probably the naive way would be to create another table and have the same attributes, like this:
However, this is a bad programming practice because we are duplicating code. Also, it can cause problems when we create our tests. To avoid this duplication, we are going to use object oriented inheritance to allow admin_users
to share the same table as that of users
.
To do that, go to your models
folder and create a new file called admin_user.rb
. If you open your user model file, user.rb
, you'll see that this class inherits from ActiveRecord::Base
. In fact, all model classes will inherit only from ActiveRecord::Base
. But, our AdminUser
will inherit from the User
class. With this code, what we are doing is creating an admin user from the existing User
class.
Now, I'm going to open my rails console, but in sandbox mode.
rails c --sandbox
The records that we create in this mode will be pulled out from the database and deleted at the end of the session, so it won't affect our development database. In this sense, this mode is more like a testing environment where we can safely try different scripts.
Let's now create a record for User
table like this:
User.create!(email: "test@test.com", password: "asdfasdf", password_confirmation: "asdfasdf")
Next, we can create an AdminUser
by running the following script:
Admin User.create!(email: "admintest@test.com", password: "asdfasdf", password_confirmation: "asdfasdf")
And this created an admin record for us. What's interesting about this code is that we don't have an AdminUser
table in our schema file, and yet this record has been created for us.
To test, you can type:
User.last
And this will show the AdminUser
object as this is the last record we created. Instead of User.last
, we can also type AdminUser.last
and it will bring up the same result. So, how did this happen?
The magic attribute that made this execution possible is the type
attribute in our users
table. This attribute controls the entire Single Table Inheritance component. When an object is created, the type
attribute checks for its inheritance. When a User
record was created, it goes to the User
class and sees that it inherits from ActiveRecord::Base
, so nothing is recorded. However, when an AdminUser
is created, it goes to the AdminUser
class and sees that it inherits from User
. So, it sets the type for that record as AdminUser
.
You can test this by storing the last record in a variable and printing its type.
u = AdminUser.last
u.type
This will display the value AdminUser
. On the other hand, try printing the type
attribute of the first record.
User.first.type
And the value will be nil because nothing was set.
Thus, we have two types of users sharing the same table. This functionality can be immensely useful when we are creating our admin dashboard in later guides. Also, this is considered to be the best way to implement sub-types of an object. Say you're creating a newspaper application where you have many types of users such as editors, readers and owners. Instead of creating different tables for each type, you can use single table inheritance for creating these records.
In the next video, we'll implement RSpec validations and test processes to help manage users.