Implementing Single Table Inheritance with Devise in Ruby on Rails

This article will discuss implementing STI(Single Table Inheritance) using Devise. First, create a project.

1
rails new devise-sti

Next, add devise gem in your Gemfile.

1
gem 'devise'

Now, run devise commands and run migration.

1
2
3
4
rails generate devise:install
rails generate devise User

rails db:create db:migrate

This will create a model called User. Now, in order to implement STI, two models will be inherited from the User model. Generate two models, Provider and Customer.

1
2
touch app/models/provider.rb
touch app/models/customer.rb

Inherit these models from User.

1
2
3
4
5
6
7
8
9
# app/models/provider.rb

class Provider < User
end

# app/models/customer.rb

class Customer < User
end

Implementing STI requires adding a type column in the parent model.

1
2
rails g migration add_type_to_users type:string
rails db:migrate

In config/routes.rb, remove the following line:

1
2
3
# config/routes.rb

devise_for :users

And add the following lines:

1
2
3
4
# config/routes.rb

devise_for :customers
devise_for :providers

Generate a welcome controller.

1
rails g controller Welcome index

In the newly created controller, add the following line:

1
2
3
# app/controllers/welcome_controller.rb

before_action :authenticate_user!

In app/views/welcome/index.html.erb, put the following:

1
2
3
4
5
6
7
8
9
# app/views/welcome/index.html.erb

<% if provider_signed_in? %>
 <p>Get ready to offer your services</p>
 <%= link_to 'Log out', destroy_provider_session_path, method: :delete %>
<% elsif customer_signed_in? %>
 <p>What kind of service do you want?</p>
 <%= link_to 'Log out', destroy_customer_session_path, method: :delete %>
<% end %>

In order to show flash messages, add these lines into app/views/layouts/application.html.erb:

1
2
3
4
# app/views/layouts/application.html.erb

<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

Finally, add the following line in app/controllers/application_controller.rb:

1
2
3
# app/controllers/application_controller.rb

devise_group :user, contains: [:customer, :provider]

Now test the implementation.

Customers

customer signup.png

customer welcome.png

Providers

provider sign up.png

provider welcome.png

There you have it! Happy implementing!