Punditry

A super-slim wrapper on top of Pundit.

Installation

Add this line to your application's Gemfile:

gem 'punditry'

And then execute:

$ bundle

Include Punditry in your application controller:

class ApplicationController < ActionController::Base
  include Punditry::Controller
end

Usage

Punditry is essentially Pundit with a few minor additions. Instead of calling authorize, you call authorize!. This delegates to authorize underneath but will also return the passed in resource, allowing you to eliminate a line of code:

# with Pundit
def update
  @post = Post.find(params[:id])
  authorize @post
  if @post.update(post_params)
    redirect_to @post
  else
    render :edit
  end
end
# with Punditry
def update
  @post = authorize!(Post.find(params[:id]))
  if @post.update(post_params)
    redirect_to @post
  else
    render :edit
  end
end

Woohoo! Big win! I also prefer the bang method to indicate that it raises an error when it is not authorized, but that's a matter of taste.

authorize! has one more addition. If you pass in a collection, it also calls policy_scope on the resource. This makes the assumption that you want to authorize index actions as well, instead of only scoping them. This is another matter of taste. Also, reflecting this assumption, Punditry verifies that every action calls authorize! including index. If you need to opt out of this, you can simply call skip_authorization in your controller:

class PostsController < ApplicationController
  skip_authorization only: :check

  def check
    # some action that does not require authorization
  end
end

Punditry::Controller gives you one other helper method. If you follow the recommendations here, then you can simply pass a resource to whitelist and get back the permitted attributes for that resource:

def update
  @post = authorize!(Post.find(params[:id]))
  if @post.update(whitelist(@post))
    redirect_to @post
  else
    render :edit
  end
end

Punditry also provides you with a base policy Punditry::Policy that all of your polices should inherit from. This policy is very basic, but using it allows you to write tests like this. Simply require punditry/rspec in your spec_helper/rails_helper.

That's it. Punditry simply leverages the power and simplicity of Pundit while making things just slightly more convenient.