Building your first authentication system may look intimidating at first. But to be honest, it's really easy. After reading this article, you will know how easy it is to create a session based authentication in rails. In this brief article, we will go over writing a session based authentication system to authenticate users and hold session data until they log out or close their browser. We will have two models, User and Item. Users will have many items but they have to login to see their items. We will build this step by step using rails 6. Let's get started! OK, let's create a new rails app. rails new simple_session cd simple_session After creating the rails app, let's continue by creating the models and controllers. We will just go over the basics in this article. You should add tests, validation and other important standards when building your app. rails generate model User string string string rails generate model Item string references rails migrate rails generate controller Users rails generate controller Items name: email: password_digest: name: user: db: We should add the 'bcrypt' gem to store password hashes in the database. So, let's do that. gem #Gemfile 'bcrypt' bundle install We will go with the easy way to use bootstrap. We will just paste the BootstrapCDN link in the head section of application.html.erb file. You can put your custom css in the custom.scss file created below. <link rel= href= integrity= crossorigin= > #application.html.erb "stylesheet" "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" "sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" "anonymous" touch app/assets/stylesheets/custom.scss OK, let's now start working on the user and items controller. We will have 3 methods in the users controller - show, new , create. The show method will be used to show users, the new method will be used to present the form to create users, and the create method will be used to create users on the back-end. You can add other methods like index, edit, update, and destroy. But since this is a basic start up, we will skip those for the users controller. We will implement all those for the items controller. You can learn more about the REST approach from this article. Wikipedia #users_controller.rb = User.find(params[:id]) end def @user = User.new end def create @user = User.new(user_params) @user.save flash[:success] = redirect_to @user render end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end < @ class UsersController ApplicationController def show user new if "Welcome to the app!" else 'new' Let's add the views. We will have a header view that will be used by the application.html.erb file. The application.html.erb is the base view that will be used by all views. #application.html.erb <!DOCTYPE html> <head> <title>RailsSession</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> </head> <body> <%= render 'layouts/header' %> <div class='container'> <% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <% end %> <%= yield %> </div> </body> </html> < > html #layouts/_header.html.erb <nav = > <div class="navbar-header"> <%= link_to "Items", '#' %> </div> <ul class="nav navbar-nav navbar-right"> <li><%= link_to "Sign up", signup_path %></li> </ul> < class "navbar mb-2" < = > div class "container-fluid" </ > div /nav> #views/items/home.html.erb <div = > <br/> <p> <%= link_to "Sign up", signup_path, class: "btn btn-primary" %> </div> class "text-center home" This is a simple guide on how to create session based authentication system < > h2 </ > h2 Please signup or login to test the app. < > p #views/shared/_error_messages.html.erb <% @user.errors.any? %> <div class="alert alert-danger"> The form contains <%= pluralize(@user.errors.count, "error") %>. </div> <ul> <% @user.errors.full_messages.each do |msg| %> <li class='text-danger'><%= msg %></li> <% end %> </ul> <% end %> if < = > div id "error_explanation" </ > div #views/users/ .html.erb <h1 = >Sign up< error_messages mb form-control mb form-control mb form-control mb form-control new class 'text-center' /h1> <div class="row"> <div class="col-md-4 offset-4"> <%= form_with(model: @user, local: true) do |f| %> <%= render 'shared/ ' %> <%= f.label :name %> <%= f.text_field :name, class: ' -1 ' %> <%= f.label :email %> <%= f.email_field :email, class: ' -1 ' %> <%= f.label :password %> <%= f.password_field :password, class: ' -1 ' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: ' -1 ' %> <%= f.submit "Create my account", class: "mt-2 btn btn-primary" %> <% end %> </div> </div> #model/user.rb { self.email = email.downcase } validates :name, : VALID_EMAIL_REGEX = validates :email, : , : { : VALID_EMAIL_REGEX }, : { : } validates :password, : , : { : } end < : class User ApplicationRecord has_many items has_secure_password before_save presence true /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i presence true format with uniqueness case_sensitive false presence true length minimum 6 #config/routes.rb Rails.application.routes.draw root get , : resources :users end do 'items#home' '/signup' to 'users#new' #views/users/show.html.erb <div = > <h3 class='text-center'> <%= @user.name %> </h3> <h3 class='text-center'> <%= @user.email %> </h3> < class "row" < = > div class "offset-4 col-md-4" </ > div /div> Ok, good work. We have finished user creation. Let's continue by creating the sessions controller. rails generate controller Sessions Let's add the following routes: get , post , delete , #config/routes.rb '/login' to: 'sessions#new' '/login' to: 'sessions#create' '/logout' to: 'sessions#destroy' Let's add the login form in the 'new.html.erb' file. #views/sessions/ .html.erb <h1 = >Log < div> new class 'text-center' in /h1> <div class="row"> <div class="col-md-6 offset-3"> <%= form_with(url: login_path, scope: :session, local: true) do |f| %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.submit "Log in", class: " mt-2 btn btn-primary" %> <% end %> </ </ > div Let's now implement the sessions controller. This part will be our main focus. We will first add the methods in the sessions controller. Not all the methods will be defined here. Some will be defined in the sessions helper. We will import the sessions helper in the applications controller which will be extended by all controllers automatically. Let's do this step by step. Let's first add the new, create and destroy methods in the sessions controller. The new method will be used for displaying the form. The create method will create the session, and the destroy method will destroy or remove the session when the user logs out. Some of the methods are implemented in the sessions helper which we will create later. user = User.find_by( params[ ][ ].downcase) user && user.authenticate(params[ ][ ]) log_in user redirect_back_or user flash.now[ ] = render log_out redirect_to root_url #sessions_controller.rb < ApplicationController class SessionsController def new end def create email: :session :email if :session :password else :danger 'Invalid email/password combination' 'new' end end def destroy end end Let's add the methods in the sessions helper. session[ ] = user.id session[ ] @current_user = User.find_by( session[ ]) !current_user. ? session.delete( ) @current_user = user == current_user redirect_to(session[ ] default) session.delete( ) session[ ] = request.original_url request.get? #app/helpers/session_helper.rb module SessionsHelper def log_in (user) :user_id end def current_user if :user_id || id: :user_id end end def logged_in? nil end def log_out :user_id nil end def current_user? (user) end def redirect_back_or (default) :forwarding_url || :forwarding_url end def store_location :forwarding_url if end end The first method (log_in) accepts user and creates a session for the user. Rails makes this easy for us. The rails way of creating a session is just using ' '. This will create a session with the user_id. The current_user method will return the current user if there is one or if there is a session present. That means if a user is logged in, the current user will be the that user. The logged_in? method just return true or false based on whether there is a current user or not. The log_out method will log out the user by deleting the session and setting the current_user to nil. The current_user? method accepts user and returns true if it's the same with the current user or false otherwise. This can be useful to restrict a user from visiting other user's details. The next two methods are useful to redirect a non logged-in user to the first visited URL after logging in. session[:user_id] = user.id Then we will import the session helper in the application controller. That means methods like logged_in? or current_user will be available to all controllers. Let's do that. SessionsHelper private logged_in? store_location flash[ ] = redirect_to login_url #application_controller.rb include def logged_in_user unless :danger "Please log in." end end The private method will be used to store location and redirect to the login form. After the user logs in, the user will be redirected back to the URL they tried to visit. But now if we try it, a user can visit the anything without logging in. That's because we have to add this method to restrict users that are not logged in. Let's add the before_action filters in the users controller. before_action , [ ] ... #users_controller.rb < ApplicationController class UsersController :logged_in_user only: :show The before_action method will be implemented before the user accesses the show method. It will go first to the logged_in_user method before going to the show method. The logged_in_user will redirect back to login form if the user hasn't logged in. We can also add another methods to be filtered in the before_action declaration, but we don't want that. The user signup should be accessed by anyone because it doesn't require login. Now it asks you to login if you visit the user page (localhost:3000/users/:id). One bad thing is that if you signup, it will ask you to login. But it doesn't make sense to login again after signing up. Let's fix that by updating the create method in the users controller file and let's also add the login link at the top. I've added the updated _header.html.erb file. @user = User.new(user_params) @user.save log_in @user flash[ ] = redirect_to @user render #users_controller.rb def create if :success "Welcome to the app!" else 'new' end end #views/layouts/_header.html.erb <nav = > <div class="navbar-header"> <%= link_to "Items", root_path, class: "mx-2" %> </div> <ul class="nav navbar-right "> <li><%= link_to "Log out", logout_path, class: "mx-2", method: :delete %></li> </ul> <ul class="nav navbar-right "> <li><%= link_to "Log in", login_path, class: "mx-2" %></li> <li><%= link_to "Sign up", signup_path, class: "mx-2" %></li> </ul> < class "navbar mb-2" < = > div class "container-fluid" < ? %> % if logged_in < %> % else < %> % end </ > div /nav> Look at how we used the logged_in? method from sessions helper to identify if a user has logged in or not. So, we are done with our session. Let's finish this tutorial by adding the items controller. Items belong to a user. A user will have many items. Rails makes it easy in creating associations. #app/models/item.rb < : : , : class Item ApplicationRecord belongs_to user validates name presence true end before_action @item = current_user.items.new @items = Item.all @item = current_user.items.build(item_params) @item.save flash[ ] = redirect_to @item render @item = current_user.items.find(params[ ]) @item = current_user.items.find(params[ ]) @item.update_attributes(item_params) flash[ ] = redirect_to @item render @item = current_user.items.find(params[ ]) @item @item.destroy flash[ ] = flash[ ] = redirect_to root_path @item = Item.find(params[ ]) private params. ( ).permit( ) #items_controller.rb < ApplicationController class ItemsController :logged_in_user def home end def new end def index end def create if :success "Item has been created!" else 'new' end end def edit :id end def update :id if :success "Item updated" else 'edit' end end def destroy :id if :success "Item has been deleted" else :alert "Error" end end def show :id end def item_params require :item :name end end Ok, we have finished the controller for items. The views are going to be similar to the user views and I will leave it as an exercise for the reader to practice it. You can also add and admin user because right now everyone can delete items. You can make it so that you a user can only delete his or her own items only. Thanks for reading the article. Contact me if you encounter any issue through email, github, linkedIn, or twitter. The repository for this article can be found . here