[Rails] Manage multiple models using devise gem

When creating a login function etc. using a Gem called devise of Rails I think there are times when you want to separate the login screen and management between the general public and the company.

I've used devise to create web applications, This is the first time I have implemented it on multiple models, so I would like to keep it as a memorandum.

environment


Ruby:   2.5.6
Rails:  5.2.4
devise: 4.7.3

Since I work in docker, it has bundle exec, If you are outside docker, please remove it and enter it.

Introducing devise

1. Install Gem

I also wanted to do Facebook authentication this time, so I added devise and omniauth-twitter to the Gemfile

Gemfile


gem 'devise'
gem 'omniauth-facebook'

And bundle install

2. Create devise related files

Enter the following command in the terminal

bundle exec rails g devise:install

I think the following words will come out

create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"
     
     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

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

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views
       
     * Not required *

===============================================================================

Check the contents of each and add them.

  1. Add the following words to config / environments / development.rb. As I was told, I will list the default URL.

config/environments/development.rb


config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
  1. Contents that set the URL when accessing config / routes.rb as root (when accessing the URL set in 1) I haven't created it yet, so I'll create it here.

Terminal


bundle exec rails g controller Posts(Controller name) index

Set the URL in config / routes.rb

config/routes.rb


Rails.application.routes.draw do
  root 'posts#index'
end
  1. Add a flash message to app / views / layouts / application.html.erb I wrote what is described for the time being.

ruby:app/views/layouts/application.html.erb


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

    <%= yield %>
  </body>
</html>
  1. It is said that you should generate a view, but I want to make 2 patterns, so I will ignore it now!

devise settings

Change the setting of config / initializers / devise.rb to make the login user 2 patterns. It was originally commented out so please look for it!

config/initializers/devise.rb(Change before)


.
#config.scoped_views = false
.
.
#config.sign_out_all_scopes = true
.

config/initializers/devise.rb(After change)


#Changed to separate login screens for multiple models
config.scoped_views = true
#Prevents logging out of one when logging out of the other when logging in with multiple models
config.sign_out_all_scopes = false

devise modeling

This time, I will make two patterns, one for the general public and one for the company!

Terminal


bundle exec rails g devise user
bundle exec rails g devise company

Check the migration file

(Since the same file other than the model name is generated, the company model file is omitted.)

db/migrate/20201112105533_devise_create_users.rb


# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # t.integer  :sign_in_count, default: 0, null: false
      # t.datetime :current_sign_in_at
      # t.datetime :last_sign_in_at
      # t.string   :current_sign_in_ip
      # t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

Check the model file

Added : omniauthable andomniauth_providers: [: facebook]to incorporate Facebook authentication.

models/user.rb


class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:facebook]
end

Bundle exec rails db: migrate where you can make changes and additions

Confirmation of ruding

Check config / routes.rb

config/routes.rb


Rails.application.routes.draw do
  devise_for :companies
  devise_for :users
  root 'postss#index'
end

Check with bundle exec rails routes

The Controller # Action part is the same for company and user. In other words, the controllers are the same and need to be changed. (* Only Controller # Action has left ... It's annoying and I can't fix it, so slide it to the right ...! )

Terminal


          Prefix Verb             URI Pattern                                                                          Controller#Action
             new_company_session GET      /companies/sign_in(.:format)                                                            devise/sessions#new
                 company_session POST     /companies/sign_in(.:format)                                                            devise/sessions#create
         destroy_company_session DELETE   /companies/sign_out(.:format)                                                           devise/sessions#destroy
            new_company_password GET      /companies/password/new(.:format)                                                       devise/passwords#new
           edit_company_password GET      /companies/password/edit(.:format)                                                      devise/passwords#edit
                company_password PATCH    /companies/password(.:format)                                                           devise/passwords#update
                                 PUT      /companies/password(.:format)                                                           devise/passwords#update
                                 POST     /companies/password(.:format)                                                           devise/passwords#create
     cancel_company_registration GET      /companies/cancel(.:format)                                                             devise/registrations#cancel
        new_company_registration GET      /companies/sign_up(.:format)                                                            devise/registrations#new
       edit_company_registration GET      /companies/edit(.:format)                                                               devise/registrations#edit
            company_registration PATCH    /companies(.:format)                                                                    devise/registrations#update
                                 PUT      /companies(.:format)                                                                    devise/registrations#update
                                 DELETE   /companies(.:format)                                                                    devise/registrations#destroy
                                 POST     /companies(.:format)                                                                    devise/registrations#create
                new_user_session GET      /users/sign_in(.:format)                                                                 devise/sessions#new
                    user_session POST     /users/sign_in(.:format)                                                                 devise/sessions#create
            destroy_user_session DELETE   /users/sign_out(.:format)                                                                devise/sessions#destroy
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format)                                                           devise/omniauth_callbacks#passthru
 user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format)                                                  devise/omniauth_callbacks#facebook
               new_user_password GET      /users/password/new(.:format)                                                            devise/passwords#new
              edit_user_password GET      /users/password/edit(.:format)                                                           devise/passwords#edit
                   user_password PATCH    /users/password(.:format)                                                                devise/passwords#update
                                 PUT      /users/password(.:format)                                                                devise/passwords#update
                                 POST     /users/password(.:format)                                                                devise/passwords#create
        cancel_user_registration GET      /users/cancel(.:format)                                                                  devise/registrations#cancel
           new_user_registration GET      /users/sign_up(.:format)                                                                 devise/registrations#new
          edit_user_registration GET      /users/edit(.:format)                                                                    devise/registrations#edit
               user_registration PATCH    /users(.:format)                                                                         devise/registrations#update
                                 PUT      /users(.:format)                                                                         devise/registrations#update
                                 DELETE   /users(.:format)                                                                         devise/registrations#destroy
                                 POST     /users(.:format)                                                                         devise/registrations#create

Ruding fix

config/routes.rb


devise_for :companies, controllers: {
    sessions:      'companies/sessions',
    passwords:     'companies/passwords',
    registrations: 'companies/registrations'
  }
  devise_for :users, controllers: {
    sessions:           'users/sessions',
    passwords:          'users/passwords',
    registrations:      'users/registrations',
    omniauth_callbacks: 'users/omniauth_callbacks'
  }

If you check again with bundle exec rails routes, the controller part will be changed safely!

Create view

This is the part that was not supported when the first rails g devise: install was executed.

Terminal


bundle exec rails g devise:views users
bundle exec rails g devise:views companies

I think each file was generated!

Creating a controller

Terminal


bundle exec rails generate devise:controllers users
bundle exec rails generate devise:controllers companies

I think that the execution result will be like this.

create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

The bottom part, a rainy day error! ?? I thought, but it's not an error. (Hot Since the controller looks like this, you need to add the following description to routes.rb ~ I give an example and teach me.

Since it was set earlier, you can ignore it!

Bonus (for those who introduce omniauth authentication)

At this rate, even if you access http: // localhost: 3000 / users / sign_in, an error will occur. Something like undefined method `omniauth_authorize_path'for ~. ..

I won't go into the Facebook authentication settings here, in app / views / users / shared / _links.html.erb The part of omniauth_authorize_path (resource_name, provider) is strange.

If you check the ruding, there is no path called omniauth_authorize_path, it should be user_facebook_omniauth_authorize_path, so let's fix it.

I didn't change the name using as ...? I thought, I wasn't sure why. Is it from the beginning ...?

Completed for the time being

Anyway! For the time being, the basic setting part is completed.

http: // localhost: 3000 / users / sign_in and http: // localhost: 3000 / companies / sign_in Whichever way you access, you will see the login screen!

Add more columns or customize if needed!

I hope this article helps someone. Thank you very much!

Recommended Posts

[Rails] Manage multiple models using devise gem
What is Rails gem devise?
[Rails] gem devise installation flow
Use devise on multiple models
[Rails] How to use gem "devise"
[Rails] List instances of multiple models
Implement a refined search function for multiple models without Rails5 gem.
[Rails] devise
[Rails] Let's manage constants with config gem
Multiple image upload function using Rails Carrierwave
Create authentication function in Rails application using devise
Implement share button in Rails 6 without using Gem
[For rails beginners] Specify transition destination after logging in to multiple Devise models
[Rails] Introducing devise
[Rails] Implementation of batch processing using whenever (gem)
[Rails] How to upload multiple images using Carrierwave
rails + devise + devise_token_auth
[Rails] Creating a breadcrumb trail using Gem gretel
[Note] Summary of rails login function using devise ①
Save data from excel file using Rails gem roo
[For Rails beginners] Implemented multiple search function without Gem
[Rails] Google, Twitter, Facebook authentication using Devise and Omniauth
[Rails] How to install a decorator using gem draper
[Rails] devise helper method
[Rails] Customize devise validation
Flash message using devise
Handle devise with Rails
[Rails] devise introduction method
[rails] About devise defaults
[Rails] Register by attribute of the same model using Devise
[Rails] Implementation of tagging function using intermediate table (without Gem)
[Rails] Implement event end function (logical deletion) using paranoia (gem)
[Rails] How to delete images uploaded by carrierwave (using devise)
Get Youtube channel information with Rails app (using Yt gem)
[Rails] Search from multiple columns + conditions with Gem and ransack
[Ruby on Rails] Infinite scrolling using gem kaminari and jscroll