cult3

Authenticating Users in Ruby on Rails

Jan 06, 2016

Table of contents:

  1. Generating the User model
  2. Writing the test
  3. Making the test pass
  4. Conclusion

Authentication is something that almost all web applications need to deal with.

But it can seem a bit intimidating for newbie programmers because authentication and security is not something you want to get wrong.

A lot of tutorials recommend that you use a gem such as Devise. Devise is great, but it’s pretty overwhelming when you are still getting to grips with Rails.

Authentication is such a common requirement of web applications, Rails actually has a solution right out of the box.

In today’s tutorial I will show you how Rails makes it incredibly easy to authenticate users with very little code.

Generating the User model

Before we can write the tests for this functionality, first we need to ask Rails to generate what we need:

bin/rails g model User username:string, email:string, password_digest:string

Here I’m generating a User model with three properties.

This will also generate the following migration:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email, index: true, null: false
      t.string :username, index: true, null: false
      t.string :password_digest, null: false

      t.timestamps null: false
    end
  end
end

As will last week’s tutorial (TDD Active Record Models with MiniTest), I’m also going to add some database specific tweaks to ensure the email and username fields are unique and that all three fields are required.

Writing the test

Next I can write the test to ensure that a user can be authenticated successfully:

def test_user_should_be_authenticable
  user = users(:philip)

  assert(user.authenticate('password'))
end

Here I’m grabbing the :philip user from the fixtures and then asserting that when I call the authenticate method with a value of password the method should return true.

If you run this test now you should see it fail.

Making the test pass

The first thing we need to do to make this test pass is to ensure we have the bcrypt gem installed. Open up your Gemfile and make sure the following line is not commented out:

gem 'bcrypt', '~> 3.1.7'

If that line is commented out, simply uncomment it and then run the following command in terminal:

bundle install

Next we need to create the fixture user that we grab in the test. Open up your users.yml file under the fixtures directory and replace the contents with your own user:

philip:
    email: test@test.com
    username: test
    password_digest: <%= BCrypt::Password.create("password", cost: 4) %>

This will generate the user for us and make it available for the test. Notice how I’m using the BCrypt::Password class to generate the hashed password.

Finally we can add the following to the User class:

class User < ActiveRecord::Base
  has_secure_password
end

This will magically make the authentication functionality from our test work. You can read more about what’s actually going on under the covers in the Rails Documentation

Now if you run that test again, you should see it pass!

Conclusion

As you can see, we didn’t really have to do much to make authentication possible in a Rails application.

Devise offers you a lot of functionality out of the box for quickly building a web application with all of the bells and whistles.

But it’s often better to go back to basics so you can better understands what’s going on at a more granular level.

Rails makes it really easy to accept and store user passwords and then authenticate them as part of your application.

This is typically a fundamental part of a web application, but it isn’t unique, and so it’s better to follow the best practices of Rails rather than trying to roll your own solution!

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.