Rails: Single Table Inheritance with Devise

Rui Freitas
Dec 9, 2019 · 2 min read

How to quickly set up two different types of users with Rails and Devise.

Sometimes we need to have different types of Users in our app. Of course, we could generate two different Devise models and have distinct signup and login flows, but there’s more than one way of achieving a similar result. In this tutorial, we’ll explore Rails’ Single Table Inheritance (STI) on a User devise model.

Let’s say that we have an app where the User model has the email, password, and other Devise related attributes, plus a first_name and last_name. Now, let’s imagine that there is one type of User we’ll call Customer and another one named Seller. For the purpose of this example, Customers can sign up for the application whereas Sellers are created by the application owners and are not able to directly sign up on the web app.

The first thing we want to do is add a column to the Users table named type. This is a reserved column in Rails used to implement STI and it will store a string with the class name of Customer or Seller.

rails g migration AddTypeToUsers type:string
rails db:migrate

We can also add these two auxiliary methods to the User class for convenience:

class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable

Then we create the classes Customer and Seller which will inherit from User.

# app/models/customer.rb
class Customer < User
# ...

Even though the instances of Customer and Seller will still be stored in the Users table, we’re now able to use ActiveRecord’s query interface out of the box as follows:

Customer.all # return all Users of the type Customer
Customer.count # return the number of Customers in the DB

We’ll now override Devise’s registration controller create action to ensure that any User that signs up through the application will automatically be of the Customer type.

# app/controllers/customers/registrations_controller.rb

And we’ll need to tell the devise routes to use our own custom RegistrationsController:

Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'customers/registrations'

That’s it. We’ve now got a system where every user who signs up will be a Customer and with Single Table Inheritance, we can add behaviour that is specific to either the Customer or Seller model by placing the code in the respective class.

Light the Fuse and Run

Web development in Ruby on Rails, React, Vue.js and Elixir

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store