0
0
RailsHow-ToBeginner · 5 min read

Create Login from Scratch in Ruby on Rails: Step-by-Step Guide

To create a login from scratch in Ruby on Rails, generate a User model with secure password using has_secure_password, then build sessions controller to handle login/logout with session management. Use forms to collect user credentials and authenticate them by checking the password securely.
📐

Syntax

This is the basic syntax to create a user model with secure password and a sessions controller for login/logout:

  • has_secure_password: Adds password hashing and authentication methods to the User model.
  • Sessions controller methods: new (login form), create (login action), destroy (logout action).
  • Use session[:user_id] to store logged-in user ID.
ruby
class User < ApplicationRecord
  has_secure_password
end

class SessionsController < ApplicationController
  def new
  end

  def create
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      session[:user_id] = user.id
      redirect_to root_path, notice: "Logged in successfully"
    else
      flash.now[:alert] = "Invalid email or password"
      render :new
    end
  end

  def destroy
    session.delete(:user_id)
    redirect_to login_path, notice: "Logged out"
  end
end
💻

Example

This example shows a simple login system with user registration, login form, and session management.

ruby
# Run these commands in terminal to set up:
# rails new login_app -d sqlite3
# cd login_app
# rails generate model User email:string password_digest:string
# rails db:migrate

# app/models/user.rb
class User < ApplicationRecord
  has_secure_password
  validates :email, presence: true, uniqueness: true
end

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def new
  end

  def create
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      session[:user_id] = user.id
      redirect_to root_path, notice: "Logged in successfully"
    else
      flash.now[:alert] = "Invalid email or password"
      render :new
    end
  end

  def destroy
    session.delete(:user_id)
    redirect_to login_path, notice: "Logged out"
  end
end

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to login_path, notice: "User created. Please log in."
    else
      render :new
    end
  end

  private

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation)
  end
end

# config/routes.rb
Rails.application.routes.draw do
  root "welcome#index"
  get "/login", to: "sessions#new"
  post "/login", to: "sessions#create"
  delete "/logout", to: "sessions#destroy"
  get "/signup", to: "users#new"
  post "/signup", to: "users#create"
end

# app/views/sessions/new.html.erb
<%= form_with url: login_path, local: true do |form| %>
  <p>
    <%= form.label :email %><br>
    <%= form.email_field :email, required: true %>
  </p>
  <p>
    <%= form.label :password %><br>
    <%= form.password_field :password, required: true %>
  </p>
  <p>
    <%= form.submit "Log in" %>
  </p>
<% end %>

# app/views/users/new.html.erb
<%= form_with model: @user, url: signup_path, local: true do |form| %>
  <p>
    <%= form.label :email %><br>
    <%= form.email_field :email, required: true %>
  </p>
  <p>
    <%= form.label :password %><br>
    <%= form.password_field :password, required: true %>
  </p>
  <p>
    <%= form.label :password_confirmation %><br>
    <%= form.password_field :password_confirmation, required: true %>
  </p>
  <p>
    <%= form.submit "Sign up" %>
  </p>
<% end %>

# app/controllers/welcome_controller.rb
class WelcomeController < ApplicationController
  def index
  end
end

# app/views/welcome/index.html.erb
<% if session[:user_id] %>
  <p>Welcome, user ID: <%= session[:user_id] %></p>
  <%= button_to "Logout", logout_path, method: :delete %>
<% else %>
  <p>You are not logged in.</p>
  <%= link_to "Login", login_path %> or <%= link_to "Sign up", signup_path %>
<% end %>
Output
<p>When running the app, users can sign up with email and password, then log in with those credentials. Successful login sets session[:user_id]. The homepage shows login status and logout button.</p>
⚠️

Common Pitfalls

  • Not using has_secure_password causes insecure password storage.
  • Forgetting to add password_digest column breaks authentication.
  • Not validating presence and uniqueness of email can cause duplicate users.
  • Not clearing session on logout leaves user logged in.
  • Using plain text passwords instead of secure hashing is unsafe.
ruby
# Wrong: User model without has_secure_password
class User < ApplicationRecord
end

# Right: User model with has_secure_password
class User < ApplicationRecord
  has_secure_password
end
📊

Quick Reference

StepDescription
Generate User modelrails generate model User email:string password_digest:string
Add has_secure_passwordAdd to User model for password hashing
Migrate databaserails db:migrate
Create SessionsControllerHandle login (new, create) and logout (destroy)
Create UsersControllerHandle user signup (new, create)
Set routesDefine routes for login, logout, signup
Create viewsForms for login and signup
Use sessionStore user ID on login, clear on logout

Key Takeaways

Use has_secure_password in User model for safe password handling.
Store logged-in user ID in session to track login state.
Always validate user input like email presence and uniqueness.
Clear session on logout to properly end user session.
Build simple forms for login and signup with Rails helpers.