Authentication in Rails
Reading
Simple Authentication with Bcrypt
Create a user model with
name
,email
andpassword_digest
with:rails generate model user name email password_digest
Run
rails db:migrate
Add these routes below
# Path: config/routes.rbget '/signup' => 'users#new'post '/users' => 'users#create'Create a users controller with a new and create action:
# Path: app/controllers/users_controller.rbclass UsersController < ApplicationControllerdef new@user = User.newenddef createuser = User.new(user_params)if user.savesession[:user_id] = user.idredirect_to root_pathelseredirect_to signup_pathendendprivatedef user_paramsparams.require(:user).permit(:name, :email, :password, :password_confirmation)endendNow create the view file where we put the signup form.
<!-- Path: app/views/users/new.html.erb --><div class="page-header"><h1>Signup!</h1></div><%= form_for(@user, html: { class: "form-horizontal", role: "form" }) do |f| %><div class="form-group"><%= f.label :name, class: "col-sm-2 control-label" %><div class="col-sm-10"><%= f.text_field :name, class: "form-control" %></div></div><div class="form-group"><%= f.label :email, class: "col-sm-2 control-label" %><div class="col-sm-10"><%= f.text_field :email, class: "form-control" %></div></div><div class="form-group"><%= f.label :password, class: "col-sm-2 control-label" %><div class="col-sm-10"><%= f.password_field :password, class: "form-control" %></div></div><div class="form-group"><%= f.label :password_confirmation, class: "col-sm-2 control-label" %><div class="col-sm-10"><%= f.password_field :password_confirmation, class: "form-control" %></div></div><%= f.submit "Submit", class: "btn btn-primary" %><% end %>Uncomment 'bcrypt' in the Gemfile
Add
has_secure_password
to add encryption of the user's password# Path: app/models/user.rbclass User < ActiveRecord::Basehas_secure_passwordendRun
bundle install
Create a sessions controller to
create
(login) anddestroy
(logout) sessions.# Path: app/controllers/sessions_controller.rbclass SessionsController < ApplicationController# logging indef newend# handle the post from the login pagedef create# Extract the email and password from the paramsemail = params[:email]password = params[:password]# Find the user by their emailuser = User.find_by(email: email)# If we found a user and their password checks outif user && user.authenticate(password)# Save the user_id in the session cookiesession[:user_id] = user.id# logged in!redirect_to root_pathelse# Nope, something went wrongredirect_to login_pathendend# logoutdef destroy# Remove their user_id from the sessionsession[:user_id] = nilredirect_to root_pathendendCreate a form for user's to login with.
<!-- path: app/views/sessions/new.html.erb --><div class="page-header"><h1>Login</h1></div><%= form_tag(login_path, html: { class: "form-horizontal", role: "form" }) do %><div class="form-group"><%= label_tag :email, class: "col-sm-2 control-label" %><div class="col-sm-10"><%= text_field_tag :email, class: "form-control" %></div></div><div class="form-group"><%= label_tag :password, class: "col-sm-2 control-label" %><div class="col-sm-10"><%= password_field_tag :password, class: "form-control" %></div></div><%= submit_tag "Submit", class: "btn btn-primary" %><% end %>Update your routes file to include new routes for the session controller.
# Path: config/routes.rbget '/login' => 'sessions#new'post '/login' => 'sessions#create'get '/logout' => 'sessions#destroy'We will add a few methods to the ApplicationController to allow us to find the current user.
# Path: app/controllers/application_controller.rbclass ApplicationController < ActionController::Base# Returns the current use if logged indef current_user@current_user ||= User.find(session[:user_id]) if session[:user_id]endhelper_method :current_user# Returns a boolean representing if the user is logged indef logged_in?!!current_userendhelper_method :logged_in?# Method to use in a filter to ensure the user is logged indef authorize!redirect_to login_path unless logged_in?endendNow we can add a
before_filter
to ensure we authorize the user. We could add this to the ApplicationController but then we would have to exclude this from controllers that do not require login (e.g. user controller, session controller, homepage controller, etc.)# path: app/controller/widgets_controller.rb# This is just an example controller, you would add this to your *own* controller filesclass WidgetsController < ApplicationControllerbefore_filter :authorize!endWe can use the
current_user
andlogged_in?
methods to customize pages, even the appliction layout file<!-- Path: app/views/layouts/application_layout.html.erb --><% if logged_in? %>Logged in: <%= current_user.email %> | <%= link_to "Logout", logout_path %><% else %><%= link_to 'Login', login_path %> | <%= link_to 'Signup', signup_path %><% end %>