Authentication in Rails Using Clearance

Clearance is a simple authentication system with email and password built by the team at Thoughtbot. It has opinionated defaults but is intended to be easy to override. The system is actively maintained, and you can follow up on GitHub.

Authentication in Rails Using Clearance

In this tutorial, you will see how to integrate Clearance into a Rails application. We will make use of a miniature application. Let’s begin!

Getting Started

You’ll start by generating your Rails application. For the purpose of this tutorial, I’ll name mine tutsplus-clearance.

rails new tutsplus-clearance -T

That will do the magic.

You’ll need bootstrap to make your application look good. Add the Bootstrap gem to your Gemfile.

#Gemfile

...
gem 'bootstrap-sass'

Install the gem by running bundle install.

Now modify application.scss  to look like this:

#app/assets/stylesheets/application.scss

@import 'bootstrap-sprockets';
@import 'bootstrap';

Clearance Setup

Open your Gemfile to add the Clearance gem.

#Gemfile

gem 'clearance'

Now install the gem.

bundle install

At this point, run the generator command to install clearance.

rails generate clearance:install

This will generate some outputs on your terminal, which look like what I have below:

create  config/initializers/clearance.rb
      insert  app/controllers/application_controller.rb
      create  app/models/user.rb
      create  db/migrate/20161115101323_create_users.rb

*******************************************************************************

Next steps:

1. Configure the mailer to create full URLs in emails:

    # config/environments/{development,test}.rb
    config.action_mailer.default_url_options = { host: 'localhost:3000' }

    In production it should be your app's domain name.

2. Display user session and flashes. For example, in your application layout:

    <% if signed_in? %>
      Signed in as: <%= current_user.email %>
      <%= button_to 'Sign out', sign_out_path, method: :delete %>
    <% else %>
      <%= link_to 'Sign in', sign_in_path %>
    <% end %>

    <div id="flash">
      <% flash.each do |key, value| %>
        <div class="flash <%= key %>"><%= value %></div>
      <% end %>
    </div>

3. Migrate:

    rake db:migrate

*******************************************************************************

When you ran the command, a couple of files were generated in your application. One such file is clearance.rb, which you can find in the config/initializers directory. A User model was also generated, and along with that you also have a migration file that looks like this:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.timestamps null: false
      t.string :email, null: false
      t.string :encrypted_password, limit: 128, null: false
      t.string :confirmation_token, limit: 128
      t.string :remember_token, limit: 128, null: false
    end

    add_index :users, :email
    add_index :users, :remember_token
  end
end

According to the output, the first thing you want to do is edit your config environment. To do that, navigate to config/environments/development.rb and add the line below, just above the end delimiter.

...
  config.action_mailer.default_url_options = { host: 'localhost:3000' }
end

Next, navigate to config/initializers/clearance.rb to edit it, and when you’re there, change the sender email address from the default to any of your choosing. This is what you will see when you open the file.

#config/initializers/clearance.rb

Clearance.configure do |config|
  config.mailer_sender = "[email protected]"
end

You can override the default configuration by pasting in the following code snippet and configuring it to your requirements.

#config/initializers/clearance.rb

Clearance.configure do |config|
  config.allow_sign_up = true
  config.cookie_domain = ".example.com"
  config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc }
  config.cookie_name = "remember_token"
  config.cookie_path = "/"
  config.routes = true
  config.httponly = false
  config.mailer_sender = "[email protected]"
  config.password_strategy = Clearance::PasswordStrategies::BCrypt
  config.redirect_url = "/"
  config.secure_cookie = false
  config.sign_in_guards = []
  config.user_model = User
end

Run the command to migrate your database.

rake db:migrate

Open your PagesController and add an index action.

#app/controllers/pages_controller.rb

class PagesController < ApplicationController
  def index
  end
end

Next, create a view for the index action you just created.

Add the code snippet below:

#app/views/pages/index.html.erb

<h1>Tutsplus Clearance</h1>
<p>Welcome to our Clearance Page.</p>

Edit your routes to:

#config/routes.rb

Rails.application.routes.draw do
  root to: "pages#index"
end

Create a partial named _navigation.html.erb inside the layouts directory. This will be used to handle everything that has to do with navigation on your application.

Paste the following code and save.

#app/views/layouts/_navigation.html.erb

<nav class="navbar navbar-inverse">
  <div class="container">
    <div class="navbar-header">
      <%= link_to 'Tutsplus-Clearance', root_path, class: 'navbar-brand' %>
    </div>
    <div id="navbar">
    <% if signed_in? %>
        <ul class="nav navbar-nav">
        <li><%= link_to 'Add Page', new_page_path %></li>
        </ul>
    <% end %>

    <ul class="nav navbar-nav pull-right">
        <% if signed_in? %>
        <li><span><%= current_user.email %></span></li>
        <li><%= link_to 'Sign out', sign_out_path, method: :delete %></li>
        <% else %>
        <li><%= link_to 'Sign in', sign_in_path %></li>
    <% end %>
  </ul>
    </div>
  </div>
</nav>

<div class="container">
  <% flash.each do |key, value| %>
    <div class="alert alert-<%= key %>">
      <%= value %>
    </div>
  <% end %>
</div>

Restricted Access

With Clearance, you can be able to create restricted access to specific pages of your choice in your application. Let’s see how it is done.

Create a view for a new action in app/views/pages, the name of the file should be new.html.erb. Paste in the code below.

#app/views/pages/new.html.erb

<h1>Restricted Page</h1>

<p>This page is restricted to authenticated users, if you can see this it means you are a superstar!</p>

Now you need to add the line below to config/routes.rb.

#config/routes.rb

...
  resources :pages, only: :new
...

Finally, go to your PagesController make it like what I have below.

#apps/controllers/pages_controller.rb

class PagesController < ApplicationController
  before_action :require_login, only: [:new]
  
  def index
  end

  def new
  end
end

In the above code, we are making use of the Clearance helper, require_login, to restrict access to the new action. To see how it works, start up your rails server by running rails server from your terminal. Point your browser to http://locahost:3000/pages/new and it should redirect you to the sign in page.

Clearance also provides routing constraints that can be used to control access.

#config/routes.rb

Rails.application.routes.draw do
  constraints Clearance::Constraints::SignedOut.new do
    root to: 'pages#index'
  end

  constraints Clearance::Constraints::SignedIn.new do
    root to: "pages#new', as: :signed_in_root
  end
end

In the code above, a different route has been created for authenticated users.

Overriding Clearance Defaults

A lot of things happen behind the scenes when you start using Clearance, things you cannot see. There might come a time when you want to customize things differently, depending on the specification of your application. Clearance allows you to override the default configuration it comes with.

To override (or generate) Clearance routes, run this command from your terminal.

rails generate clearance:routes

Your routes file should now look like this:

#config/routes.rb

Rails.application.routes.draw do
  resources :passwords, controller: "clearance/passwords", only: [:create, :new]
  resource :session, controller: "clearance/sessions", only: [:create]

  resources :users, controller: "clearance/users", only: [:create] do
    resource :password,
      controller: "clearance/passwords",
      only: [:create, :edit, :update]
  end

  get "/sign_in" => "clearance/sessions#new", as: "sign_in"
  delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
  get "/sign_up" => "clearance/users#new", as: "sign_up"
  root to: "pages#index"
  resources :pages, only: :new
end

The command will also set the config.routes setting to false in your config/initializers/clearance.rb file. This means that the custom file which has just been generated will be used.

To generate views for modification, run:

rails generate clearance:views

Some of the files that will be generated include:

  app/views/passwords/create.html.erb
  app/views/passwords/edit.html.erb
  app/views/passwords/new.html.erb
  app/views/sessions/_form.html.erb
  app/views/sessions/new.html.erb
  app/views/users/_form.html.erb
  app/views/users/new.html.erb
  config/locales/clearance.en.yml

You will see a prompt in your terminal asking to overwrite your app/views/layouts/application.html.erb file. Choose the option you want.

Layouts

By default, Clearance uses your application’s default layout. If you would like to change the layout that Clearance uses when rendering its views, simply specify the layout in an initializer.

Clearance::PasswordsController.layout "my_passwords_layout"
Clearance::SessionsController.layout "my_sessions_layout"
Clearance::UsersController.layout "my_admin_layout"

Helper Methods

Clearance provides you with helper methods that can be used in your controllers, views, and helpers. These methods include signed_in?, signed_out?, and current_user. For example:

<% if signed_in? %>
  <%= current_user.email %>
  <%= button_to "Sign out", sign_out_path, method: :delete %>
<% else %>
  <%= link_to "Sign in", sign_in_path %>
<% end %>

Conclusion

Clearance has a lot to offer you when it comes to authentication, so be sure to try it out in your next project. You can learn more by checking out the GitHub page.