Authentication in Rails
Authentication is how you verify who a user is. Rails provides tools to build authentication from scratch or use gems like Devise.
Rails 8+ Built-in Authentication
Rails 8 includes a built-in authentication generator:
bash
1rails generate authenticationThis creates:
- User model with secure password
- Session controller
- Password reset functionality
- Current model for accessing the current user
Building Authentication from Scratch
1. Create User Model
bash
1rails generate model User email:string:uniq password_digest:string
2rails db:migrate2. Add has_secure_password
ruby
1# app/models/user.rb
2class User < ApplicationRecord
3 has_secure_password
4
5 validates :email, presence: true,
6 uniqueness: { case_sensitive: false },
7 format: { with: URI::MailTo::EMAIL_REGEXP }
8 validates :password, length: { minimum: 8 }, if: :password_required?
9
10 before_save :downcase_email
11
12 def self.authenticate_by(email:, password:)
13 user = find_by(email: email.downcase)
14 user&.authenticate(password) || nil
15 end
16
17 private
18
19 def downcase_email
20 self.email = email.downcase
21 end
22
23 def password_required?
24 password_digest.nil? || password.present?
25 end
26endAdd bcrypt to your Gemfile:
ruby
1# Gemfile
2gem 'bcrypt', '~> 3.1.7'3. Create Sessions Controller
ruby
1# app/controllers/sessions_controller.rb
2class SessionsController < ApplicationController
3 def new
4 # Login form
5 end
6
7 def create
8 user = User.authenticate_by(
9 email: params[:email],
10 password: params[:password]
11 )
12
13 if user
14 session[:user_id] = user.id
15 redirect_to root_path, notice: 'Logged in successfully!'
16 else
17 flash.now[:alert] = 'Invalid email or password'
18 render :new, status: :unprocessable_entity
19 end
20 end
21
22 def destroy
23 session.delete(:user_id)
24 redirect_to root_path, notice: 'Logged out successfully!'
25 end
26end4. Create Registration Controller
ruby
1# app/controllers/registrations_controller.rb
2class RegistrationsController < ApplicationController
3 def new
4 @user = User.new
5 end
6
7 def create
8 @user = User.new(user_params)
9
10 if @user.save
11 session[:user_id] = @user.id
12 redirect_to root_path, notice: 'Account created successfully!'
13 else
14 render :new, status: :unprocessable_entity
15 end
16 end
17
18 private
19
20 def user_params
21 params.require(:user).permit(:email, :password, :password_confirmation)
22 end
23end5. Add Routes
ruby
1# config/routes.rb
2Rails.application.routes.draw do
3 get 'signup', to: 'registrations#new'
4 post 'signup', to: 'registrations#create'
5
6 get 'login', to: 'sessions#new'
7 post 'login', to: 'sessions#create'
8 delete 'logout', to: 'sessions#destroy'
9
10 # Or RESTful:
11 resource :session, only: [:new, :create, :destroy]
12 resource :registration, only: [:new, :create]
13end6. Application Controller Helpers
ruby
1# app/controllers/application_controller.rb
2class ApplicationController < ActionController::Base
3 helper_method :current_user, :logged_in?
4
5 private
6
7 def current_user
8 @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
9 end
10
11 def logged_in?
12 current_user.present?
13 end
14
15 def authenticate_user!
16 unless logged_in?
17 redirect_to login_path, alert: 'Please log in to continue'
18 end
19 end
20end7. Protecting Controllers
ruby
1class ArticlesController < ApplicationController
2 before_action :authenticate_user!, except: [:index, :show]
3
4 def new
5 @article = current_user.articles.build
6 end
7
8 def create
9 @article = current_user.articles.build(article_params)
10 # ...
11 end
12endLogin Form
erb
1<!-- app/views/sessions/new.html.erb -->
2<h1>Log In</h1>
3
4<%= form_with url: login_path, local: true do |f| %>
5 <div class="field">
6 <%= f.label :email %>
7 <%= f.email_field :email, autofocus: true, required: true %>
8 </div>
9
10 <div class="field">
11 <%= f.label :password %>
12 <%= f.password_field :password, required: true %>
13 </div>
14
15 <div class="field">
16 <%= f.check_box :remember_me %>
17 <%= f.label :remember_me, "Remember me" %>
18 </div>
19
20 <%= f.submit "Log In" %>
21<% end %>
22
23<p>
24 Don't have an account? <%= link_to "Sign up", signup_path %>
25</p>Registration Form
erb
1<!-- app/views/registrations/new.html.erb -->
2<h1>Sign Up</h1>
3
4<%= form_with model: @user, url: signup_path do |f| %>
5 <% if @user.errors.any? %>
6 <div class="errors">
7 <% @user.errors.full_messages.each do |msg| %>
8 <p><%= msg %></p>
9 <% end %>
10 </div>
11 <% end %>
12
13 <div class="field">
14 <%= f.label :email %>
15 <%= f.email_field :email, autofocus: true %>
16 </div>
17
18 <div class="field">
19 <%= f.label :password %>
20 <%= f.password_field :password %>
21 </div>
22
23 <div class="field">
24 <%= f.label :password_confirmation %>
25 <%= f.password_field :password_confirmation %>
26 </div>
27
28 <%= f.submit "Sign Up" %>
29<% end %>Navigation with Auth Links
erb
1<!-- app/views/shared/_navigation.html.erb -->
2<nav>
3 <%= link_to "Home", root_path %>
4
5 <% if logged_in? %>
6 <span>Welcome, <%= current_user.email %></span>
7 <%= link_to "Profile", profile_path %>
8 <%= button_to "Log Out", logout_path, method: :delete %>
9 <% else %>
10 <%= link_to "Log In", login_path %>
11 <%= link_to "Sign Up", signup_path %>
12 <% end %>
13</nav>Remember Me (Persistent Session)
ruby
1class User < ApplicationRecord
2 has_secure_password
3 has_secure_token :remember_token
4end
5
6class SessionsController < ApplicationController
7 def create
8 user = User.authenticate_by(email: params[:email], password: params[:password])
9
10 if user
11 if params[:remember_me] == "1"
12 user.regenerate_remember_token
13 cookies.permanent.encrypted[:remember_token] = user.remember_token
14 end
15 session[:user_id] = user.id
16 redirect_to root_path
17 else
18 # ...
19 end
20 end
21
22 def destroy
23 cookies.delete(:remember_token)
24 session.delete(:user_id)
25 redirect_to root_path
26 end
27end
28
29class ApplicationController < ActionController::Base
30 def current_user
31 @current_user ||= if session[:user_id]
32 User.find_by(id: session[:user_id])
33 elsif cookies.encrypted[:remember_token]
34 User.find_by(remember_token: cookies.encrypted[:remember_token])
35 end
36 end
37endThis is the foundation for user authentication in Rails!
