When building a web app, you don't want every user to have access to every single part of the app, so you will want to restrict access. That's why we add authentication to our app. In this tutorial, we will create a simple authentication for your Ruby On Rails app.
To follow along with this tutorial, you will need:
- Some basic knowledge of Ruby On Rails
- A text editor(I am using sublime text)
- Ruby, Rails, Node and Yarn installed on your computer.
To get started, create a new rails application and navigate to the directory:
rails new authentication cd authentication
Next, create a welcome page and set the root to index action in
To do this, run the following command:
rails g controller welcome index
Now, let's set up the route in
config/routes.rb like so:
Rails.application.routes.draw do get 'welcome', to: 'welcome#index' root to: 'welcome#index' end
The generator creates a
welcome_controller.rb file in
class WelcomeController < ApplicationController def index end end
It also creates an
index.html.erb file in
app/views/welcome. By default, rails render a view that corresponds with the name of the controller. Now, add some content for that page in the file:
In the database, we will not like to store our passwords in plain text. Instead, we encrypt the password. We can do this by uncommenting
gem 'bcrypt', '~> 3.1.7' in
Gemfile and run
bundle install to install the gem.
gem 'bcrypt', '~> 3.1.7' bundle install
Let's continue by adding the model and controllers.
Create a user model with attributes,
rails g model User email:string password_digest:string
rails db:migrate to migrate it to the database. The
password_digest creates a password_digest field in the users table.
has_secure_password and some validations.
class User < ApplicationRecord has_secure_password validates :email , presence: true, uniqueness: true end
Here, before a user gets saved to the database, an email should be present, and it should also be unique.
Let's create a registration controller by running the following command:
rails g controller registrations new
Add the following to
class RegistrationsController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) if @user.save session[:user_id] = @user.id redirect_to root_path else render :new end end private def user_params params.require(:user).permit(:email, :password, :password_confirmation) end end
The code snippet above creates a new user and saves it to the database. The
new action initializes a new object in the User model and stores it as an instance variable that can be accessed in the views. The
create action creates the user instance and sets its id to a session which redirects to the
root_path if successful and renders
new when it fails.
Create a sign_up form in
<%= form_with model: @user, url: sign_up_path do |f| %> <%= f.label :email %> <%= f.text_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label password_confirmation %> <%= f.password_field :password_confirmation %> <%= f.submit "Sign Up" %> <% end %>
and update the route:
Rails.application.routes.draw do get 'welcome', to: 'welcome#index' root to: 'welcome#index' resources :users get 'sign_up', to: 'users#new' post 'sign_up', to: 'users#create' end
$ rails s to start the development server and visit
localhost:3000/sign_up to create a new user.
Create the sessions controller by running the code:
rails g controller sessions new create destroy
and add the following code to
class SessionsController < ApplicationController def new end def create user = User.find_by(email: params[:email]) if user.present? && user.authenticate(params[:password]) session[:user_id] = user.id redirect_to root_path else render :new end end def destroy session[:user_id] = nil redirect_to sign_in_path end end
create method for
SessionsController finds the user based on the email in the database. If a user is present and the password matches, the id of the user instance is stored in a session and they are logged in. Otherwise, we will be redirected to the sign_in page.
destroy method sets the user session to nil and logs out the user.
<h1>Sign In </h1> <%= form_with url: sign_in_path do |f| %> <%= f.label :Email %> <%= f.text_field :email %> <%= f.label :Password %> <%= f.password_field :password %> <%= f.submit "Sign in" %> <% end %>
and set up the routes:
Rails.application.routes.draw do get 'welcome', to: 'welcome#index' root to: 'welcome#index' resources :users get 'sign_up', to: 'users#new' post 'sign_up', to: 'users#create' get 'sign_in', to: 'sessions#new' post 'sign_in', to: 'sessions#create' delete 'logout', to: 'sessions#destroy' end
Now, a user can sign_in by visiting
localhost:3000/sign_in in the browser.
Add the following in
app/controllers/application_controller.rb to create a
class ApplicationController < ActionController::Base before_action :set_current_user def set_current_user if session[:user_id] Current.user = User.find_by(id: session[:user_id]) end end end
set_current_user method will return the current user if it finds one or if there is a session present. Also, since all controllers inherit from the
set_current_user will be accessible in all the controllers.
Let's create a
current.rb file in
app/models and add the following:
class Current < ActiveSupport::CurrentAttributes attribute :user end
This code will allow us to call
Current.user in our views.
app/views/welcome/index.html.erb and update it with the following:
<h1>Welcome Page</h1> <% if Current.user %> Logged in as: Current.user.email<br> <%= button_to "Sign Out", logout_path, method: :delete %> <% else %> <%= link_to "Sign up", sign_up_path %> <%= link_to "Sign In", sign_in_path %> <% end %>
This code checks if
Current.user is present and provides a
sign_out button when signed in. Otherwise, a
sign_in link is seen.
Congrats, we have successfully built a simple authentication in Ruby On Rails without relying on any gem. I hope you found this tutorial easy to follow, and If you have any questions, please add your query in the comments section. Thank you!