Add Authentication to Your Rails App With bcrypt

Ashley Colletti
4 min readFeb 5, 2017

--

If you are creating a Rails app that requires users to log in, you will need to add authentication. This will allow you to keep track of which information belongs to which user while managing who has access to it. For this to work, you need to have a database. In this example, I’ve already created a CRUD app called contacts-app with a postgreSQL database that has users and contacts.

The Ruby gem, bcrypt, is a secure hash algorithm for safely storing passwords. To use bcrypt, uncomment it from your Gemfile and run bundle install in Terminal.

To start adding authentication, you will need to create a User model.

This is telling rails to generate a model called “User” with the attributes “name”, “email”, and “password_digest”. The default attribute type is string, so you don’t need to specify it here since that is the type of data we will be gathering. If you wanted to write it the long way, it would be name:string.

bcrypt requires that you use password_digest as your attribute name. Once your model is loaded, migrate your database by running rake db:migrate Open app/models/user.rb and add the method has_secure_password to your User class. has_secure_password and password_digest work together in bcrypt, so both need to be present for it to work.

Next, open config/routes.rb and add the bolded “new” and “create” routes to your RESTful routing.

Rails.application.routes.draw doget ‘/contacts’ => ‘contacts#index’get ‘/contacts/new’ => ‘contacts#new’
post ‘/contacts’ => ‘contacts#create’
get ‘/contacts/:id’ => ‘contacts#show’get ‘/contacts/:id/edit’ => ‘contacts#edit’
patch ‘/contacts/:id’ => ‘contacts#update’
delete ‘/contacts/:id’ => ‘contacts#destroy’get ‘/signup’ => ‘users#new’
post ‘/users’ => ‘users#create’
end

“new” will be for your signup page view, and the“create” action will store the user’s information in your database. To set this up, run rails generate controller users in your terminal window. In app/controllers/users_controller.rb you can define your “create” method to take in the user’s input.

The highlighted portion displays a flash message letting the user know if their signup was successful or not. This works because I have installed the bootstrap gem.

In order for the user to give you their information, create a new view file: app/views/users/new.html.erb to display the input fields. Erb tags <%=%> allow you to mix in ruby code with html provided your file ends in .html.erb.

<h2> Create Account</h2><%=form_tag “/users”, method: :post do%>
<div>
<%= label_tag :name%>
<%= text_field_tag :name%>
</div>
<div>
<%= label_tag :email%>
<%= text_field_tag :email%>
</div>
<div>
<%= label_tag :password%>
<%= password_field_tag :password%>
</div>
<div>
<%= label_tag :password_confirmation%>
<%= password_field_tag :password_confirmation%>
</div>

<%= submit_tag “Sign Up”, class: “btn btn-default”%>
<%end%>
Throughout this process, you can check that everything is working by running rails server in Terminal and navigating to localhost:3000/signup in your browser. Your page should look something like this. I used bootstrap to add a navbar.

Now that your users can sign up, they need a way to log in and out. Add a sessions controller with rails generate controller sessions Add sessions routes in config/routes.rb right below the ones you added for users.

 get ‘/login’ => ‘sessions#new’
post ‘/login’ => ‘sessions#create’
get ‘/logout’ => ‘sessions#destroy’

Create a new view page for users to log in from: app/views/sessions/new.html.erb Note that I’ve used password_field_tag instead of a text_field_tag so the characters will not show as they are typed.

<h1>Login</h1>
<%= form_tag ‘/login’, method: :post do %>
<div>
<%= label_tag :email %>
<%= text_field_tag :email%>
</div>
<div>
<%= label_tag :password %>
<%= password_field_tag :password %>
</div>
<%= submit_tag “Submit” %>
<%end%>

Add the new actions in routes.rb to app/controllers/sessions_controller.rb Flash messages have been added to show if the log in is successful or not. If successful, they are sent to the home page /contacts, otherwise, they are redirected back to /login.

class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
flash[:success] = ‘Successfully Logged In!’
redirect_to ‘/contacts’
else
flash[:warning] = “Invalid Username or Password”
redirect_to ‘/login’
end
end
def destroy
session[:user_id] = nil
flash[:success] = “Successfully Logged Out!”
redirect_to ‘/login’
end
end

In app/controllers/application_controller.rb you can add a helper method so you are able to use it as a keyword throughout your app.

class ApplicationController < ActionController::Base 
protect_from_forgery with: :exception

def current_user @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authenticate_user!
redirect_to ‘/login’ unless current_user
end
end

You can add the helper method in contacts_controller.rb to make sure users can’t see the contacts page without logging in.

def index
if current_user
@contacts = current_user.contacts
render “index.html.erb”
else
flash[:warning] = “You must be logged in to see this page”
redirect_to ‘/login’
end
end

Finally, you can go back through your application.html.erb file and include signup, login, and logout URLs to your routes. The helper method can be used to only show the appropriate links based on the user’s session status. It can also help you link contacts to a specific user if you decide to create has_many and belongs_to associations.

End Result:

--

--