Authentication in Ruby: build a simple online form with Ruby on Rails
Tags: rails, ruby, beginners, codenewbie
Published: 2024-04-12 14:20:59

## Table of Contents
&nbsp;1. [Introduction](#introduction)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1. [Setting Up a New Rails App](#setting-up-a-new-rails-app)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.2. [Implementing Authentication](#implementing-authentication)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a. [Adding Authentication with Bcrypt](#adding-authentication-with-bcrypt)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b. [Setting Up the User Model](#setting-up-the-user-model)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.3. [Signing Up](#signing-up)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.4. [Logging In](#logging-in)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.5. [Logging Out](#logging-out)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.6. [Conclusion](#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](https://www.ruby-lang.org/). You can install Rails by running the following command:

```bash
gem install rails
```

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

```bash
rails new rails_app
```

_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
```

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

```
rails server
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gusfuuxul2afv6h2ui0t.png)

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:

```ruby
gem 'bcrypt', '~> 3.1.7'
```

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:

```bash
rails generate model User email:string password_digest:string
```

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:

```ruby
# 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

```

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

```ruby
  get "sign_up", to: "registration#new"
  post "sign_up", to: "registration#create"
```
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`:

```ruby
# 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

```

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](https://medium.com/@anslie/the-private-method-and-its-uses-in-a-rails-app-7fcd71d5f1ea#:~:text=Another%20reason%20we%20use%20the,to%20localhost%3A3000%2Fusers.)

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`

```html
<!-- 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 %>

```

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:

```ruby
  get "log_in", to: "sessions#new"
  post "log_in", to: "sessions#create"
```
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:

```ruby
# 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
```

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 our`new.html.erb` view:

```html
<!-- 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 %>
```

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

```ruby
delete "logout", to: "sessions#destroy"
```
In our `sessions_controller`, under our `create` method, we have the `destroy` methof.

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

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](https://dev.to/dumebii/beginner-ruby-on-rails-build-a-simple-online-store-with-ruby-on-rails-2egl) on getting started with Ruby on Rails and building your first application! Check it out [here](https://dev.to/dumebii/beginner-ruby-on-rails-build-a-simple-online-store-with-ruby-on-rails-2egl)

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](www.linkedin.com/in/dumebi-okolo).

[Cover Image](https://www.google.com/url?sa=i&url=https%3A%2F%2Fstevepolito.design%2Fblog%2Frails-authentication-from-scratch&psig=AOvVaw0IZzb3kbT1baNdXQ4yyLF2&ust=1713017093655000&source=images&cd=vfe&opi=89978449&ved=0CBQQjhxqFwoTCOCjr-DsvIUDFQAAAAAdAAAAABAl)