Ruby-on-Rails authentication tutorial with Devise
Rails authentication
Ruby-on-Rails lack of internal, built-in authentication mechanism is something often claimed by developer for the next Rails version.
Devise seems the go-to, default gem for authentication, despite being heavily discussed on forums (like this Reddit discussion).
For bootrails we have chosen Rodauth, which is really brilliant.
But this article, I will try to present you the functionality of the Devise gem via a common test case: a quick authentication with username and password
Setup an empty Rails app
We assume you are using an Ubuntu Linux distribution with the following installed:
- ruby
- rails
- bundler
So let’s create an empty Rails application.
Prerequisites
To follow this article you will need to check if you have installed the prerequisites, if something is missing you need to install it first to proceed.
1
2
3
4
5
6
7
8
9
$/workspace> ruby -v
ruby 3.1.2p20 // you must have at least version 3
$/workspace> rails -v
Rails 7.0.3.1
$/workspace> bundle -v
Bundler version 2.3.7 // you must have at least version 2
How do I get set up with Rails?
Since this is a hands-on tutorial we should start by creating an empty Rails application and we can build upon it.
Let’s assume that we will have one controller in our application, the PagesController, which will handle all requests coming for our two-page website:
- Home
- Exclusive content
As you can imagine we need to control the access to the “Exclusive content” to only the registered users while the home page will be accessible by anyone.
1
2
3
4
5
6
7
8
// Create a new Rails app
$/workspace> rails new my-app
// Enter the newly created folder
$/workspace> cd my-app
// Create our 'PagesController' controller with the 'exclusive' view
$/workspace/my-app> bin/rails generate controller PagesController exclusive
How do I get set up with Devise?
Firstly open up with your editor your Gemfile and add this:
1
gem 'devise'
then run these:
1
2
3
4
5
6
7
8
9
10
11
12
// add the gem to the dependencies
$/workspace/my-app> bundle install
// install the gem
$/workspace/my-app> bin/rails g devise:install
// create the User model
$/workspace/my-app> bin/rails g devise user
// Run the DB Migration
$/workspace/my-app> bin/rails db:migrate
Check the work so far
Run the development server
1
2
// start the Puma built-in web server for testing
$/workspace/my-app> bin/rails server
and point your browser to the following URL: http://localhost:3000. You should see something like this:
Try to visit also the Exclusive content page http://localhost:3000/pages/exclusive, you can see it without any problem, right?
1
2
// close the web server
$/workspace/my-app> Ctr-C
Welcome to the Devise world!
The Devise gem will create all the required code (Model, DB migrations) and routes to create user accounts, sign in, sign out, reset passwords, etc.
What options do I have with Devise
The following main routes have already been created:
- Register a new user http://localhost:3000/users/sign_up
- Authenticate a user http://localhost:3000/users/sign_in
You also have a User model ready to support the handling of the users of your application.
1
2
3
4
5
6
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
end
Devise will provide also the option:
- to verify if a user is signed in by using the following helper: user_signed_in?
- to access the current signed-in user by using: current_user
- or to access the session via: user_session
Create a user for our testing
Point your browser at: http://localhost:3000/users/sign_up
and create a new user. A simple form like this will be presented:
just set a demo email and a password for authentication. For example:
user: test@test.com
pass: password
Let’s add also the main links of SignUp, SignIn, and Logout
With your editor open the layout file: my-app/app/views/layouts/application.html.rb
and add this:
1
2
3
4
5
6
7
8
9
<div>
<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
<%= link_to "Logout", destroy_user_session_path, method: :delete, :class => 'navbar-link' %>
<% else %>
<%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> |
<%= link_to "Sign in", new_user_session_path, :class => 'navbar-link' %>
<% end %>
</div>
Like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
<head>
<title>MyApp</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<div>
<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
<%= link_to "Logout", destroy_user_session_path, method: :delete, :class => 'navbar-link' %>
<% else %>
<%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> |
<%= link_to "Sign in", new_user_session_path, :class => 'navbar-link' %>
<% end %>
</div>
<%= yield %>
</body>
</html>
A simple user authentication
As we wrote earlier the page with the “Exclusive content” contains some content that must be accessible only to registered users. A simple Register and Login/Logout functionality is sufficient. So Where do we begin?
You guessed correctly! No need to write any extra code for the common functionality above.
Open with your editor the my-app/app/controllers/pages_controller.rb
and add this line:
before_action :authenticate_user!
1
2
3
4
5
6
class PagesController < ApplicationController
before_action :authenticate_user!
def exclusive
end
end
Try to visit now the Exclusive content page http://localhost:3000/pages/exclusive, you can not see it now, right? It redirects you to the login page.
Use the user credentials you just created and you will be redirected to the exclusive content. You can see now at the top the Logout option.
Where you can go from here
You can always improve and expand on existing code, here are some ideas:
- change the User model and add your code to enhance it.
- add Roles and Permissions and connect them with the user Model.
- change the styling and the structure of the scaffolded forms to fill your requirements.
The above test case is a simple one but surely you will face more complex situations in real-life web applications. Nowadays the requirements are higher and web applications are getting more complex. Consider that:
- you can implement a 2FA Authentication
- or implement authentication as well for API’s specific endpoints.
These can be supported by the Devise gem ( you can learn more about the Devise gem by reading their documentation ) but we will write about them in future articles! ;-)
Conclusion
Congratulations! You have just created a web application with user authentication in a few minutes. Remember that you have just tasted a small piece of the capabilities of the devise gem. Keep learning!
As you can see with a few commands you can build a very powerful authentication system. The Devise ecosystem provides the flexibility to a developer to forget about trivial things like user authentication and concentrate more on the core functionalities of the web application.
Enjoy!!