DEV Community

Kevin Luo
Kevin Luo

Posted on • Edited on

Setup very basic authentication with Devise in Rails 7

Introduction

devise is the most popular gem in Rails for authentication. However, it's also the most confusing gem for beginners. It is so confusing that it even suggests not using it if you're new to Rails or web development in its readme.

I'd like to show you how to install and set up devise for its very basic functionalities so you can have a starting point to play around with it.

Environment

  • Ruby 3.1.2
  • Rails 7.0.4.3
  • devise 4.9.2

Steps

Initialize a new Rails app



$ rails new basic_devise_with_rails7


Enter fullscreen mode Exit fullscreen mode

For later use, we also add an index page



$ rails generate controller pages index


Enter fullscreen mode Exit fullscreen mode

It will create

  1. a new controller, PagesController
  2. a new action index in PagesController

Set up devise

1. install devise



gem 'devise', '~> 4.9.2'


Enter fullscreen mode Exit fullscreen mode

Then run bundle install to install it.

2. Setup default settings

devise cannot be used right after installation. You need to initialize it.
To initialize devise, execute



$ rails generate devise:install


Enter fullscreen mode Exit fullscreen mode

It will also pop up several suggestions for settings. I'm going to list those suggestions and how to deal with them.



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 *


Enter fullscreen mode Exit fullscreen mode

According to the suggestions above, we can do the following things.

1. Set up default URL for action_mailer

You can add it in config/environments/development.rb



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


Enter fullscreen mode Exit fullscreen mode

2. define a root path in route config/routes.rb

We just added pages/index in the routes so we can set it as the root path.



Rails.application.routes.draw do
  root 'pages#index'
  get 'pages/index'
end


Enter fullscreen mode Exit fullscreen mode

3. add flash message templates

We can add the HTML below in app/views/layouts/application.html.erb to show flash messages.



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


Enter fullscreen mode Exit fullscreen mode

4. No need to customize Devise views

We don't need to customize Devise views because we only need the basic functionality

All settings are ok now!

Login & Sign up

Create User model

We need to choose a kind of Model to be used for authentication, that is, you want who can sign up and log in. That model is usually called User so we execute:



$ rails generate devise User


Enter fullscreen mode Exit fullscreen mode

It will

  • create app/models/user.rb
  • create db/migrate/2023xxxxxxxxx_devise_create_users.rb
  • insert devise_for :users into config/routes.rb

Then execute



$ rails db:migrate


Enter fullscreen mode Exit fullscreen mode

Link to Devise pages

We need a link to the login page, so we update the code in app/views/pages/index.html.erb and make it the Home page



<h1>Home</h1>
<%= link_to 'Sign in', new_user_session_path %>


Enter fullscreen mode Exit fullscreen mode

and start rails by



$ rails start


Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000, you should see this page:

Home page

Yeah, it feels so plain and even ugly. Please don't mind it because it's not a CSS-styling tutorial...

Click Sign in, you should see the login page

Sign in page

We don't have any users at this point so we click Sign Up link and we will be led to the Sign Up page

Sign up page

Register a new user by entering the email and password and then clicking the Sign up button. You will be redirected to the Home index page.

Sign up successfully

Checkpoint 1

At this point, we can review what we've done so far. Check the database to see what happened there. I'm using DBeaver here see. You can use whatever tool you like.
You can find a users table is created successfully.

users table

There are many columns in the users table, but it's easy to know that

  • email should store the email of a user
  • encrypted_password should store the password word of a user and it's encrypted

Check the content of the users table, you can find the row of the user we just created with its corresponding data.

users table content

Show User information

Click the Sign in link again, it will show You are already signed in

Already signed in

It seems like you will be signed in automatically after signing up successfully so we are redirected to the Home. Whatever, it does not feel right. Since Sign in is not a valid link, maybe we don't need to see it when we're signed in. We can update the code in app/views/pages/index.html.erb



<% if user_signed_in? %>
  <h1>Welcome Home, <%= current_user.email %></h1>
<% else %>
  <h1>Home</h1>
  <%= link_to 'Sign in', new_user_session_path %>
<% end %>


Enter fullscreen mode Exit fullscreen mode

Refresh the page and get

show user information

Checkpoint 2

There are three helpers you can use in controllers and views based on which model is used for devise. We have set User so we have:

  • user_signed_in? return true if now a user is signed in
  • current_user return the User instance of the current signed-in user, it'll be nil if there's no signed-in user
  • user_session return a hash session stored in the cookie. We can ignore it for now.

Logout

It would be nice if we can log out and let the page return to its initial state. We can update the code again in app/views/pages/index.html.erb



<% if user_signed_in? %>
  <h1>Welcome Home, <%= current_user.email %></h1>
  <%= link_to 'Sign out', destroy_user_session_path, data: { turbo_method: :delete } %>
<% else %>
  <h1>Home</h1>
  <%= link_to 'Sign in', new_user_session_path %>
<% end %>


Enter fullscreen mode Exit fullscreen mode

The page will be like:

Home page with sign out

Click Sign out button, then you can be signed out!

Sign out successfully

You can go to Log in page again and login by entering the email and the password.

Log in again

Checkpoint 3

For signing out, we want to send a DELETE HTTP request to the server. Rails 7 has taken turbo-rails as default. Therefore, we can add data: { turbo_method: :delete } to achieve that.



<%= link_to 'Sign out', destroy_user_session_path, data: { turbo_method: :delete } %>


Enter fullscreen mode Exit fullscreen mode

Congratulations! You just finished the very basic usage of Sign Up/Login/Log out by devise!

Let's review some more details about it in the following sections.

Devise Routings

We use some mysterious paths out of nowhere in the view:

  • new_user_session_path
  • destroy_user_session_path

Where are these paths come from?

When we did rails generate devise User, it inserted devise_for :users into config/routes.rb and those paths are generated dynamically.

You can use rails routes to check what routes that line generates:
Routes

Flash messages

Why there was text showed up on the top of the page? For example,

  • Welcome! You have signed up successfully
  • You are already signed in.
  • Signed out successfully.

Do you remember you added



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


Enter fullscreen mode Exit fullscreen mode

in app/views/layouts/application.html.erb.

It can show messages stored in



flash[:notice]
# or
flash[:alert]


Enter fullscreen mode Exit fullscreen mode

flash div

Other

Why do we need to set the default URL for config.action_mailer?

There are several functionalities of devise will send email to users. For example, it can send a confirmation letter after a user registers to prevent spam accounts.
If you want to deploy it to production and you have a domain can be used then set it in config/environments/production.rb



config.action_mailer.default_url_options = { host: 'your-domain.com' }

Enter fullscreen mode Exit fullscreen mode




Why I need to login by email and why password has to be at least 6 characters long?

rails generate devise:install generates 2 files:

  • config/initializers/devise.rb
  • config/locales/devise.en.yml You can configure all the devise settings in devise.rb, including iwhether you want to use username to log in or set that password must be at least 8 characters long.

Conclusion

devise is not a simple gem to learn and use at this moment. However, it's a very powerful tool. If you only run Rails as an API server, it can also support JWT-based authentication. You can check out its wiki page to learn more about it https://github.com/heartcombo/devise/wiki/How-Tos

I hope this article can help you begin the journey with devise.

Code

All the code can be found at https://github.com/kevinluo201/basic_devise_with_rails7

Top comments (2)

Collapse
 
pckrishnadas88 profile image
krishnadaspc

Great explanation. Keep up the good work.

Collapse
 
chetanam profile image
Chetan

Great