Authentication in Ruby: build a simple online form with Ruby on Rails

dumebii

Dumebi Okolo

Posted on April 12, 2024

Authentication in Ruby: build a simple online form with Ruby on Rails

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.
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

How to Sett 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 on Ruby on Rails

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 in Ruby on Rails

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.

Build a Sign Up function with Ruby on Rails

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.

Build a Log In function with Ruby on Rails

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.

Build a Logging Out function with Ruby on Rails

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

💖 💪 🙅 🚩
dumebii
Dumebi Okolo

Posted on April 12, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related