Using Clearance with RailsAdmin

Jessie Young

These days, I find myself implementing RailsAdmin on almost every consulting project that I’m on. While RailsAdmin is not a replacement for a custom or complex admin interface, it’s a great way to give non-technical stakeholders access to the data being created and updated in a Rails app. And it takes just a few minutes to set up!

Where there is an admin interface, there is also authentication. Most of the documentation out there covers how to integrate RailsAdmin with Devise. But setting up RailsAdmin with Clearance is easy, too!

Here is a step by step guide on how to set up RailsAdmin with Clearance authentication:

Step 1: Set up Clearance

# Gemfile
gem "clearance"
bundle install
rails generate clearance:install

Running the Clearance generator creates a migration. Clearance’s generated migration will either create the users table or add only the columns necessary for Clearance to an existing users table. Before we run the migration, let’s add a boolean column to indicate whether a user is an admin or not.

# db/migrate/20140808213224_create_users.rb
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users  do |t|
      t.timestamps null: false
      t.boolean :admin, null: false, default: 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

Now we’re ready to run the migration:

rake db:migrate

Step 2: Write a test

We want to be sure that only admin users can see our admin dashboard, so we’ll start with some feature specs that test this behavior. See this overview of testing Rails applications for more detail on how thoughtbot tests Rails applications.

# spec/features/admin_dashboard_spec.rb
feature "Admin dashboard" do
  scenario "visitor is admin" do
    admin = create(:admin)

    visit rails_admin_path(as: admin)

    expect(page).to have_content("Site Administration")
  end

  scenario "visitor is not an admin user" do
    user = create(:user)

    visit rails_admin_path(as: user)

    expect(page).to have_content("You are not permitted to view this page")
  end
end

The tests above are using Clearance::BackDoor to sign the user in directly. This is one of Clearance’s super awesome tools that speeds up tests and makes writing feature specs a breeze.

Before these tests will run properly, we need to set up admin and user factories:

# spec/factories.rb
factory :user do
  email { "test@example.com" }
  password { "password" }

  factory :admin do
    admin { true }
  end
end

When we run our feature spec, our app does not recognize rails_admin_path, so it’s time to set up RailsAdmin.

Step 3. Set up RailsAdmin

Add the gem:

# Gemfile
gem "rails_admin"
bundle install

Tell RailsAdmin where we want it mounted (here, we’re choosing at “/admin”)

# config/routes.rb
Rails.application.routes.draw do
  mount RailsAdmin::Engine => "/admin", as: "rails_admin"

When we run the tests again, we find that one of our tests is passing. Woot!

Unfortunately, the one that is failing is the spec that makes sure only admin users can view RailsAdmin. That is no bueno.

Time to configure RailsAdmin to redirect non-admin users (we’re assuming here that we have a root path defined in our routes.rb file):

# config/initializers/rails_admin.rb
RailsAdmin.config do |config|
  config.authorize_with do
    unless current_user.admin?
      redirect_to(
        main_app.root_path,
        alert: "You are not permitted to view this page"
      )
    end
  end

  config.current_user_method { current_user }
end

Now our tests both pass! But don’t celebrate too quickly. There is one final step we need to take care of: If we create an admin user in console, start our server, and log in as that admin user, we will see the following form at “/admin/user/new”:

rails admin new user

RailsAdmin assumes that because we have a password field, we will also have a password_confirmation field. If we try to fill these fields out and save a new user, we will get an error like this:

ActiveRecord::UnknownAttributeError in RailsAdmin::MainController#new
unknown attribute: password_confirmation

Clearance doesn’t have a password_confirmation field, so we are unable to create or update users in RailsAdmin out of the box. We can use the RailsAdmin DSL for configuring which fields to expose:

# config/initializers/rails_admin.rb
RailsAdmin.config do |config|

  ...

  config.model "User" do
    edit do
      field :admin
      field :email
      field :password
    end
  end
end

If we restart our server and re-load the admin dashboard, we’ll see that only the admin, email, and password fields are exposed and we can create a new user from within RailsAdmin.

We’re done! Now we can wow our teammates with the awesome admin dashboard we put together in just a few minutes.

While we will probably include a sign out link in our main app, we’ve found that admin users frequently look for a sign out link from within RailsAdmin. Since RailsAdmin looks for Devise when deciding whether or not to show a sign out link, we need to provide a little workaround:

# lib/rails_admin_logout_link.rb
RailsAdmin::ApplicationHelper

  module RailsAdmin
    module ApplicationHelper
      def logout_path
        main_app.send(:sign_out_path) rescue false
      end
    end
  end

  class Devise
    def self.sign_out_via
      :delete
    end
  end

After restarting our server, we see a bright red “log out” link in the upper right hand corner of RailsAdmin:

rails admin log out