Authentication in Ruby: build a simple online form with Ruby on Rails
Dumebi Okolo
Posted on April 12, 2024
Table of Contents
1. Introduction
1.1. Setting Up a New Rails App
1.2. Implementing Authentication
a. Adding Authentication with Bcrypt
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
Once Rails is installed, you can generate a new Rails app by running:
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
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'
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
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
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"
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
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 %>
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"
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
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 %>
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"
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
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.
Posted on April 12, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.