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_passwordcauses insecure password storage. - Forgetting to add
password_digestcolumn 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
| Step | Description |
|---|---|
| Generate User model | rails generate model User email:string password_digest:string |
| Add has_secure_password | Add to User model for password hashing |
| Migrate database | rails db:migrate |
| Create SessionsController | Handle login (new, create) and logout (destroy) |
| Create UsersController | Handle user signup (new, create) |
| Set routes | Define routes for login, logout, signup |
| Create views | Forms for login and signup |
| Use session | Store 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.