DEV Community

Cover image for 🚀Simple Authentication in Ruby on Rails: a step by step guide
Dumebi Okolo
Dumebi Okolo

Posted on

🚀Simple Authentication in Ruby on Rails: a step by step guide

Table of Contents

 1. Introduction

       1.1. Setting Up a New Rails App

       1.2. Implementing Authentication

             a. Adding Authentication with Bcrypt

             b. Setting Up the User Model

       1.3. Signing Up

       1.4. Logging In

       1.5. Logging Out

       1.6. Conclusion

Introduction

Providing the security of web applications is paramount, and one of the binding aspects of it is authentication. It fosters the safe and secure sign-up, login, and logout of users.
In this article, we'll dive deeper into the implementation of authentication in a Rails app, utilizing the built-in features and popular gems that are available.
From configuring authentication to managing user sessions, this article will cover everything you need to know to make your application secure and reliable.

We will begin by starting up a simple Rails application

Setting Up a New Rails App

To create a new Rails app, you should have Ruby and Rails installed on your machine. You can find how to install Ruby on your local machine using the Ruby docs. You can install Rails by running the following command:

gem install rails
Enter fullscreen mode Exit fullscreen mode

Once Rails is installed, you can generate a new Rails app by running:

rails new rails_app
Enter fullscreen mode Exit fullscreen mode

On a Windows OS, you would need to add bin/rails before your ruby prompt for the terminal to be able to recognize it. This applies to all your work on the terminal.

This will create a new Rails application with the name rails_app.

Next, navigate into the new app directory:

cd rails_app
Enter fullscreen mode Exit fullscreen mode

To confirm that everything is set up correctly, you can run the Rails server, typing this on your terminal:

rails server
Enter fullscreen mode Exit fullscreen mode

If the server starts without any errors, you should be able to access your new Rails app by visiting http://localhost:3000 in your web browser.
You should see a page like this on your browser

Rails start-up page

With the basic Rails app set up, we can now proceed to implement authentication features: user sign-up, login, and logout.

Implementing Authentication

Authentication is an important aspect of most web applications, allowing users to securely sign up, log in, and log out.

Adding Authentication with Bcrypt

Rails provides built-in support for secure password hashing using the bcrypt gem. We can add the gem to our Gemfile:

gem 'bcrypt', '~> 3.1.7'
Enter fullscreen mode Exit fullscreen mode

After installing the gem, we can use the has_secure_password method in our User model. This method adds methods to set and authenticate against a BCrypt password.

Setting Up the User Model

The first thing we'd do is to create a User model to store user information. We can generate the model and its migration using the following command:

rails generate model User email:string password_digest:string
Enter fullscreen mode Exit fullscreen mode

This will create a User model with email and password_digest columns. The password_digest column is used by Rails to store the hashed password instead of the plain-text password, ensuring better security.

Next, we'll add validations to the User model to ensure that the email is unique and present, and the password meets certain requirements:

# app/models/user.rb
class User < ApplicationRecord
  include ActiveModel::SecurePassword
  has_secure_password
  attr_accessor :password_digest

  validates :email, presence: true

  validates_format_of :email,  with: /\A[^@\s]+@[^@\s]+\z/, message: "Must be a valid email address"
  validates :password, presence: true
  validates :password_confirmation, presence: true
end

Enter fullscreen mode Exit fullscreen mode

The validates_format_of is a Ruby method that helps us set the format in which we want either our email address or password to be written.

The has_secure_password method adds methods to set and authenticate against a BCrypt password. It also requires the password_digest column to be present in the database.

Signing Up

We will need to create a route that our users can use to access the Signup page.
In our routes.rb file, we will have

  get "sign_up", to: "registration#new"
  post "sign_up", to: "registration#create"
Enter fullscreen mode Exit fullscreen mode

The get request for the registration#new route will lead to the views we will create for our Signup page.
The post request for the registration#create route is a post request that we will use to send information our user will enter back to the database.

After this, we will create the controller to handle these actions.
Under our controllers folder, we will create a new file, registration_controller:

# app/controllers/registration_controller.rb
class RegistrationController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to root_path, notice: "Successfully created account!"

    else
      render :new
    end
  end

  private
  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation)
  end
end

Enter fullscreen mode Exit fullscreen mode

In our create method, we invoke the .save method in Ruby telling our application that if a new entry is made into the User model, it should save it to the database.

If you are wondering why we created the private method, you can read more on it here

Now, we will create our view. In your views folder, we will create a directory named registration and a file under it named new.html.erb

<!-- app/views/registration/new.html.erb -->

<h1> Sign up Page </h1>

<%= form_with model: @user, local: true, data: { turbo: false }, url: sign_up_path do |form| %>

    <% if @user.errors.any? %>
        <div class="alert alert-danger">
        <% @user.errors.full_messages.each do |message|%>
        <div class='m-5'>
        <%= message %> <% end %>
        </div>
        </div>
    <% end %>
    <div class="mb-3">
        <%= form.label :email, "Email Address" %>
        <%= form.text_field :email, class: "form-control", placeholder: "myname@email.com" %>
    </div>
    <div class="mb-3">
        <%= form.label :password, "Password" %> 
        <%= form.password_field :password,  class: "form-control", placeholder: "strong password"%>
    </div>

    <div class="mb-3">
        <%= form.submit "Sign Up", class: 'btn btn-primary' %>
    </div>
<% end %>

Enter fullscreen mode Exit fullscreen mode

This view displays a form where users can enter their email and password.

Logging In

To allow users to log in, we'll need a controller action and a view for the login form as well as a route to direct our users to it.
Just as we did in the registration route, in our routes.rb we will have:

  get "log_in", to: "sessions#new"
  post "log_in", to: "sessions#create"
Enter fullscreen mode Exit fullscreen mode

The get request is to render our view for the log in page while our post request is to send information back to the database.

In our SessionsController, we will have:

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController

  def new
  end

  def create
    user = User.find_by(email: params[:email])
    if user.present? && user.authenticate(params[:password])
      session[:user_id] = user.id
      redirect_to root_path, notice: "Successfully logged in"
    else
      flash[:alert] = 'Invalid email or password'
      render :new
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

The create method is telling Rails to check if the information it is receiving through the post request matches what is present in the database, and if so to redirect the user to the root page with a, 'Successfully logged in' notice.

In ournew.html.erb view:

<!-- app/views/sessions/new.html.erb -->
<h1>Log In</h1>

<%= form_with url: sessions_path, local: true do |form| %>
  <div>
    <%= form.label :email %>
    <%= form.text_field :email %>
  </div>

  <div>
    <%= form.label :password %>
    <%= form.password_field :password %>
  </div>

  <%= form.submit "Log In" %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

In the SessionsController#create action, we find the user by their email and authenticate them using the authenticate method provided by has_secure_password. If the authentication is successful, we store the user's ID in the session and redirect them to the root path. Otherwise, we render the login form again with an error message.

Logging Out

To allow users to log out, in our homepage, we can add a link or button that leads the user to logout.
We do not need to create a view for this. We will just update our routes in our routes.rb file and update our sessions_controller.

In our routes.rb file, we will be making a delete request to the database that will correspond to a destroy method in our sessions_controller.

delete "logout", to: "sessions#destroy"
Enter fullscreen mode Exit fullscreen mode

In our sessions_controller, under our create method, we have the destroy methof.

# app/controllers/sessions_controller.rb
def destroy
  session[:user_id] = nil
  redirect_to root_path, notice: 'Logged out successfully.'
end
Enter fullscreen mode Exit fullscreen mode

This action simply removes the user_id from the session, effectively logging the user out and redirecting them to the root path.

Conclusion

In this article, we've covered the basics of implementing authentication in a Rails app, including signing up, logging in, and logging out. We've used built-in Rails features and the bcrypt gem to securely store and authenticate user passwords. This is just a beginner article and is a good starting point, but you may want to improve your knowledge by learning additional features like password reset functionality, account activation, and stronger password requirements for production applications.

I wrote an article on getting started with Ruby on Rails and building your first application! Check it out here

I hope this article has been good and helpful to you. I am still in the process of learning and becoming a better dev myself.
Let's connect on LinkedIn.

Cover Image

Top comments (4)

Collapse
 
iankcode profile image
Ian Kamau

Awesome blog. Love it ❤️

Collapse
 
dumebii profile image
Dumebi Okolo

Thank you so much. ❤️

Collapse
 
chrisebuberoland profile image
Chris Ebube Roland

A fantastic read.
Great job!

Collapse
 
dumebii profile image
Dumebi Okolo

Thanks, Chris!