Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save rahilwazir/2c7c30bed4ea3327e1d6 to your computer and use it in GitHub Desktop.

Select an option

Save rahilwazir/2c7c30bed4ea3327e1d6 to your computer and use it in GitHub Desktop.
Simple Authentication in Rail 4 Using Bcrypt

#Simple Authentication with Bcrypt

This guide is for adding authentication to a vanilla Ruby on Rails app using Bcrypt and has_secure_password.

The steps below are based on Ryan Bates's approach from Railscast #250 Authentication from Scratch (revised).

You can see the final source code here: repo. I began with a stock rails app using rails new gif_vault

##Steps

  1. Create a user model with a name, email and password_digest (all strings) by entering the following command into the command line: rails generate model user name email password_digest.

    Note: If you already have a user model or you're going to use a different model for authentication, that model must have an attribute names password_digest and some kind of attribute to identify the user (like an email or a username).

  2. Run rake db:migrate in the command line to migrate the database.

  3. Add these routes below to your routes.rb file. Notice I also deleted all the comments inside that file. Don't forget to leave the trailing end, though.

    # config/routes.rb
    
    GifVault::Application.routes.draw do
        
        # This route sends requests to our naked url to the *cool* action in the *gif* controller.
        root to: 'gif#cool'
    
        # These routes will be for signup. The first renders a form in the browse, the second will 
        # receive the form and create a user in our database using the data given to us by the user.
        get '/signup' => 'users#new'
        post '/users' => 'users#create'
    
    end
  4. Create a users controller:

    # app/controllers/users_controller.rb
    
    class UsersController < ApplicationController
    
    end
  5. Add a new action (for rendering the signup form) and a create action (for receiving the form and creating a user with the form's parameters.):

    # app/controllers/users_controller.rb
    
    class UsersController < ApplicationController
    
        def new
        end
    
        def create
        end   
    
    end
  6. Now create the view file where we put the signup form.

    # app/views/users/new.html.erb
    
    <h1>Signup!</h1>
    
    <%= form_for :user, url: '/users' do |f| %>
    
      Name: <%= f.text_field :name %>
      Email: <%= f.text_field :email %>
      Password: <%= f.password_field :password %>
      Password Confirmation: <%= f.password_field :password_confirmation %>
      <%= f.submit "Submit" %>
    
    <% end %>

    A note on Rail's conventions: This view file is for the new action of the users controller. As a result, we save the file here: /app/views/users/new.html.erb. The file is called new.html.erb and it is saved inside the views folder, in a folder we created called users.

    That's the convention: view files are inside a folder with the same name as the controller and are named for the action they render.

  7. Add logic to create action and create the private user_params method to sanitize the input from the form (this is a new Rails 4 thing and it's required).

class UsersController < ApplicationController

def new
end

def create
  user = User.new(user_params)
  if user.save
    redirect_to '/'
  else
    redirect_to '/signup'
  end
end

private

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

end ```

  1. Go to the User model file and add has_secure_password.

    # app/models/user.rb
    
    class User < ActiveRecord::Base
    
      has_secure_password
    
    end
  2. Go to your Gemfile and uncomment the 'bcrypt' gem.

    source 'https://rubygems.org'
    
    # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
    gem 'rails', '4.0.4'
    
    # Use sqlite3 as the database for Active Record
    gem 'sqlite3'
    
    ...
    
    # Use ActiveModel has_secure_password
    gem 'bcrypt', '~> 3.1.7'
    
    ...
  3. Run bundle install from the terminal then restart your rails server.

  4. Create a sessions controller.

    # app/controllers/sessions_controller.rb
    
    class SessionsController < ApplicationController
    
      def new
      end
    
      def create
      end
    
      def destroy
      end
    
    end
  5. Create a form for user's to login with.

    <!-- app/views/sessions/new.html.erb -->
    
    <h1>Login</h1>
    
    <%= form_tag '/login' do %>
    
      Email: <%= text_field_tag :email %>
      Password: <%= password_field_tag :password %>
      <%= submit_tag "Submit" %>
    
    <% end %>
  6. Update your routes file to include new routes for the sessions controller.

    GifVault::Application.routes.draw do
    
      root to: 'gif#cool'
    
      get '/login' => 'sessions#new'
      post '/login' => 'sessions#create'
      get '/logout' => 'sessions#destroy'
    
      get '/signup' => 'users#new'
      post '/users' => 'users#create'
      
    end
  7. Update the sessions_controller with the logic to log users in and out.

      # app/controllers/sessions_controller.rb
    
      def create
        user = User.find_by_email(params[:email])
        # if the user exists AND the password entered is correct
        if user && user.authenticate(params[:password])
          # save the user id inside the browser cookie. This is how we keep the user logged in when they navigate around our website.
          session[:user_id] = user.id
          redirect_to '/'
        else
          redirect_to '/login'
        end
      end
    
      def destroy
        session[:user_id] = nil
        redirect_to '/login'
      end
  8. Update the application controller with new methods to set the current_user if cookies work and to authorize.

    # app/controllers/application_controller.rb
    
    class ApplicationController < ActionController::Base
      # Prevent CSRF attacks by raising an exception.
      # For APIs, you may want to use :null_session instead.
      protect_from_forgery with: :exception
    
      def current_user
        current_user ||= User.find(session[:user_id]) if session[:user_id]
      end
      helper_method :current_user
    
      def authorize
        redirect_to '/login' unless current_user
      end
    
    end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment