Authentication Adding User Authentication with Devise
In this demonstration, I will show how to add user authentication with the Devise gem.
General Steps
In general, the steps for adding user authentication are as follows.
-
Step 1 Install and Set Up Devise Gem. This step installs the Devise gem and runs the configuration generate command.
-
Step 2 Generate User Model. This step creates the User model with Devise attributes and adds seeds.
-
Step 3 Add Sign In/Sign Out/Sign Up Links. This step changes the current views to include links to sign in, sign out, or sign up.
-
Step 4 Require Sign-In for Controller Actions. This step adds a before-action to the controllers which requires users to be signed in before utilizing that controller’s actions.
Adding Authentication to the Quiz Me App
To demonstrate the steps for adding authentication, we will be adding it to the Quiz Me App.
Step 1 Install and Set Up Devise Gem
Substep Install Devise Gem. To install Devise, we add the following to the bottom of the Gemfile.
# Authentication
gem 'devise'
Afterwards, run bundle install
in the terminal.
Substep Run Devise Installation Command. To finish the installation, we need to run the following command.
rails generate devise:install
If devise has been installed correctly you should see the following message in the terminal:
Some setup you must do manually if you haven\'t yet:
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.
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
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>
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
Step 2 Generate User Model
Substep Generate Devise User Model. To create the User model, we run the following command.
rails generate devise User
The command will generate a new migration (something like db/migrate/20191113155313_devise_create_users.rb
), a new model class (app/models/user.rb
), and it will add the following declaration to routes.rb which creates all the standard Devise routes for the User class:
devise_for :users
Substep Add Seeds. To add seeds for the User model, we create them like any other seed object. By default Devise Users only need an email and a password.
user1 = User.create!(
email: "bob@email.com",
password: "password"
)
user2 = User.create!(
email: "alice@email.com",
password: "password"
)
# Quiz and Question Seeds...
Step 3 Add Sign In/Sign Out/Sign Up Links
To include the necessary links, we will be editing the navbar of the Quiz Me app.
When visiting a site that includes authentication, we expect to be offered the chance to sign up or sign in. If we are already signed in, we want to be offered the ability to sign out or view our profile. Devise already takes care of the views and forms, but we need to handle the logic of when and where these links are displayed. We can do this with the help of the user_signed_in?
Devise helper which checks to see if a user is signed in, and the current_user
helper which retrieves the currently signed-in User.
The relevant route helpers that Devise provides for us are:
- new_user_session_path: Sign-In
- destroy_user_session_path: Sign-Out
- new_user_registration_path: Sign-Up
- edit_user_registration_path: Edit Profile
In the file views/shared/_navbar.erb.html
, add a second <ul> block that includes the following code:
<nav class="navbar navbar-expand-lg navbar-light bg-light px-5">
<a class="navbar-brand" href="#">QuizMe</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item <%= active_class(quizzes_path) %>">
<%= link_to 'Home', quizzes_path, class: 'nav-link' %>
</li>
</ul>
<ul class="navbar-nav">
<% if user_signed_in? %>
<li class="nav-item <%= active_class(edit_user_registration_path) %>">
<%= link_to "Hi, #{current_user.email}", edit_user_registration_path, class: 'nav-link' %>
</li>
<li class="nav-item">
<%= link_to 'Sign Out', destroy_user_session_path, method: :delete, class: 'nav-link' %>
</li>
<% else %>
<li class="nav-item <%= active_class(new_user_session_path) %>">
<%= link_to 'Sign In', new_user_session_path, class: 'nav-link' %>
</li>
<li class="nav-item <%= active_class(new_user_registration_path) %>">
<%= link_to 'Sign Up', new_user_registration_path, class: 'nav-link' %>
</li>
<% end %>
</ul>
</div>
</nav>
Test It!
To confirm that we made this change correctly, start the server, navigate to http://localhost:3000 and see that there are sign-in and sign-up links on the right side of the navbar.
After registering, the links should change to “Hi, {current user}” and “Sign Out”
Step 4 Require Sign-In for Controller Actions
To keep signed-out users from accessing any Quiz or Question actions that we don’t want them to see, we can add a before_action :authenticate_user!
statement to our controllers. This will redirect any unauthenticated users to the sign-in page before executing any actions in the controllers. For the Quizzes controller, we exempt the index action from requiring authentication because we are using the quiz index page as our home page.
class QuizzesController < ApplicationController
before_action :authenticate_user!, except: [:index]
# Controller Actions...
end
class QuestionsController < ApplicationController
before_action :authenticate_user!
# Controller Actions...
end
For more information on before_action
statements, see the explanation of filters in the Rails Guides. :authenticate_user!
is a method provided by Devise.
Test It!
To confirm that we made this change correctly, we sign out and navigate to http://localhost:3000/quizzes/1 and see that you are redirected to the sign-in page. If you then enter login information, you will be taken to http://localhost:3000/quizzes/1 as originally requested.
Conclusion
Following the above steps, we have now an app that requires authentication and keeps unauthenticated users from accessing its primary functions.