Posted November 1, 2015 in Code 5 minutes

Pundit - Part 1

Pundit is a Ruby gem for managing authorization in Rails. If you need to do things like allow certain users to access an admin dashboard but prohibit access to others, you’re in the right place.

Now, let’s get to it. Shall we?

What’s Under the Hood?

Pundit is all about policies. They define access through a collection of basic true or false methods.

Policies correspond to your controllers. For example, if you have a users_controller.rb then you’ll probably want a users_policy.rb. They go together like peas and carrots.

Pundit In Action

The access request begins within the controller by calling the authorize method:

class SuppliersController < ApplicationController

  def show
    @supplier = Supplier.find(params[:id])
    authorize(@supplier) # <--- Pundit call to the SupplierPolicy

  # moar controller...

Generally, the only parameter to the authorize method will be the record you are seeking to access.

Pundit infers three things when authorize(@supplier) is called.

  1. There is a current_user available
  2. There is a SupplierPolicy (inferred from the @supplier parameter)
  3. There is a boolean method of the same name (e.g. show?) defined within the SupplierPolicy that returns a truthy response.

With that information, the authorize method looks up the correct policy and we continue the journey…

That’s Just the Policy Sir

Now that we’ve instantiated the correct policy, let’s what we got.

class SupplierPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user # <--- This is the current_user
    @record = record # <--- This is the variable @supplier

  def show? # <--- See, they match!
    user.admin? # <--- Returns true or false

As the SupplierPolicy is initialized we set up an instance variable @user with our current_user. We also set the @record instance variable to our @supplier variable we passed in to the authorize method call.

With both the user and record available, we can now run all manner of checks to see if we should allow a given action to continue.

In the example, we call the admin? method on user (which we set up with the attr_reader). The admin? method should return either true or false, in turn meaning the show? method will return true or false.

Note: If you use Rails Enums to store your classification attributes, you’ll get boolean methods for free. Otherwise, we’ll need to make them ourselves.

So, if the user is an admin, show? will be true and we’ll allow him to access the show action.

You’ll find these types of checks are common in most applications but you can also have checks based on the record as well. For example, if Supplier has a :published attribute, we may also want something like…

class SupplierPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record

  def show?
    user.admin? || record.published?

Now we can allow admins to view any supplier record and at the same time allow non admin users to only access supplier records that have been published.

The Rest of the Story

That’s it for today but there’s more to come. In part 2 we will take a look at scopes and limiting access to lists of records.

Until then, cheers!