How to create a super simple authentication system in Ruby on Rails without devise [log in]
Problem
How to create a super simple authentication system in Ruby on Rails without devise. This article is going to focus on the login functionality.
Situation
Authenticating users helps ensure that only authorized individuals can access certain features or protected resources.
While Rails provides the popular Devise gem for handling authentication, there may be scenarios where you prefer a lightweight solution or want to understand the underlying mechanics.
In this article, we will explore how to create a super simple authentication system in Ruby on Rails without relying on the Devise gem.
To be more specific, we are going to focus on the login activity.
Solution
Configure users;
Configure a place to be redirected to;
Manage user in the session;
User
Create user
bin/rails generate scaffold User name:string password:digest
By using the scaffold generator, you can quickly generate a basic CRUD interface for the User model, including database migration, model code, controller code, views, and tests. This scaffolding serves as a starting point for building a fully functional user management system in your Rails application.
Perform migration
bin/rails db:migrate
Install bcrypt
Uncomment the following line
gem 'bcrypt', '~> 3.1.7'
and run
bundle install
The `bcrypt` gem is a Ruby implementation of the `bcrypt` password hashing algorithm. It provides a secure way to store and verify passwords in a hashed format.
The gem automatically generates a unique salt for each password digest. Salting adds an extra layer of security by making each password hash unique, even if two users have the same password.
Admin (Optional)
This step is optional. I'm going to generate an AdminController.
This controller and view are going to be reached when the user is logged in.
Generate controller
rails generate controller Admin index
As you already know, the rails generate controller command touches:
A view file based on the action's name;
A controller;
A css file;
A helper file;
A route.
Index admin view page
# app/views/admin/index.html.erb
<h1>Welcome</h1>
<p>
It's <%= Time.now %>
Index admin action
# app/controllers/admin_controller.rb
class AdminController < ApplicationController
def index
end
end
Authentication Approach
In order to accomplish our super simple authentication system, we're going to choose sessions.
There are a lot of other options out there, however, this article is going to focus on Sessions.
Controller
Generate the controller
bin/rails generate controller Sessions new create destroy
The new
action is responsible for rendering the login form. It displays the form where users can enter their email and password to authenticate.
The create
action is responsible for processing the login form submission. It retrieves the user's email and password from the form parameters and attempts to authenticate the user.
The destroy
action is responsible for logging out the user and clearing their session. It removes the user_id
from the session to mark the user as logged out.
By implementing these actions, the SessionsController
handles the authentication process by allowing users to log in (new and create actions) and log out (destroy action).
output
create app/controllers/sessions_controller.rb
route get 'sessions/new'
get 'sessions/create'
get 'sessions/destroy'
invoke erb
create app/views/sessions
create app/views/sessions/new.html.erb
create app/views/sessions/create.html.erb
create app/views/sessions/destroy.html.erb
invoke test_unit
create test/controllers/sessions_controller_test.rb
invoke helper
create app/helpers/sessions_helper.rb
invoke test_unit
invoke assets
invoke scss
create app/assets/stylesheets/sessions.scss
Name routes
# config/routes.rb
controller :sessions do
get 'login' => :new
post 'login' => :create
delete 'logout' => :destroy
end
This code block in the config/routes.rb
file defines routes for the SessionsController using the controller
method. The controller
method allows you to group multiple routes under a specific controller.
By using the controller
method, the routes for the SessionsController are defined concisely, indicating the HTTP method and the corresponding action in the controller. This approach follows the convention of the RESTful routing in Rails, where specific URLs map to specific actions in a controller.
Login
Login form
# app/views/sessions/new.html.erb
<%= form_tag do %>
<h2>Please Log In</h2>
<div class="field">
<%= label_tag :name, 'Name:' %>
<%= text_field_tag :name, params[:name] %>
</div>
<div class="field">
<%= label_tag :password, 'Password:' %>
<%= password_field_tag :password, params[:password] %>
</div>
<div class="actions">
<%= submit_tag "Login" %>
</div>
<% end %>
The form_tag
method generates an HTML form tag. In this case, since no specific URL is provided, the form will submit to the same URL that rendered the view. The form will use the default HTTP method, which is POST
.
The code generates a login form with two fields: one for the name/email and another for the password. The user can enter their credentials and click the "Login" button to submit the form.
Implement login
# app/controllers/sessions_controller.rb
def create
user = User.find_by(name: params[:name])
if user.try(:authenticate, params[:password])
session[:user_id] = user.id
redirect_to admin_url
else
redirect_to login_url, alert: "Invalid user/password combination"
end
end
The create
action in the SessionsController handles the login process.
It retrieves the user based on the provided name/email, attempts to authenticate the user using their password, and either grants access by setting the user ID in the session or redirects back to the login page with an error message.
The authenticate
method is typically provided by the has_secure_password
feature in Rails, which automatically adds password encryption and authentication functionality to the User model.
Logged user
Retrieve logged user
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
helper_method :current_user
private
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end
end
The current_user
method in the ApplicationController
is a helper method that provides access to the currently logged-in user throughout the application.
The helper_method
declaration makes the current_user
method available in the view templates as well. By using helper_method
, the method can be accessed from both controllers and views.
By having the current_user
method available in the ApplicationController
, other controllers and views can call this method to access information about the currently authenticated user. It is commonly used to implement authentication checks, authorization logic, and personalization based on the logged-in user's data.
Show logged user
# app/views/layouts/application.html.erb
<% if current_user %>
Logged in as <%= current_user.name %>
<%= link_to 'Logout', logout_path, method: :delete %>
<% else %>
<%= link_to 'Login', login_path %>
<% end %>
Test
Create a new user
Log in
User logged in
Celebrate
Let's become business friends
Final thoughts
I hope this article helped you. Let me know if you have any questions.
Your thoughts, suggestions and corrections are more than welcome.
By the way, feel free to drop your suggestions on new blog articles.
Hope to see you next time.