Cannie

Build Status Code Climate

Cannie is a gem for authorization/permissions checking on per-controller/per-action basis.

Installation

Add this line to your application's Gemfile:

gem 'cannie'

And then execute:

$ bundle

Or install it yourself as:

$ gem install cannie

Usage

Define permissions

Permissions are defined in Permissions class, which could be generated by Rails generator:

rails g cannie:permissions

Than you can define all the permissions you want:

class Permissions
  include Cannie::Permissions

  # allow action on controller
  allow :index, on: :posts

  # or if controller is namespaced
  allow :index, on: 'namespace/controller'

  # few actions for controller
  allow [:index, :show], on: :posts

  # many actions for many controllers
  allow [:index, :show], on: [:posts, :comments]

  # few rules inside controller scope
  controller :posts do
    allow :show
    allow :new
  end

  # namespaced controllers
  namespace :admin do
    controller :users do
      allow [:index, :show]
    end
  end
end

Also its possible to pass conditions for allow calls:

allow :index, on: :posts, if: ->{ user.admin? }

or

allow :index, on: :posts, unless: ->{ user.guest? }

or

allow :index, on: :posts, if: &:admin?

or

allow :index, on: :posts, unless: &:admin?

These conditions are executed in context of Permissions object and its possible to use user method to access user that was passed to Permissions::initialize.

Checking permissions

To be sure that permissions checking is handled in each action of your controller, add check_permissions method call to your controllers:

class PostsController < ApplicationController
  check_permissions

  #...
end

It's also possible to set a condition by specifying :if or :unless options for check_permissions call:

class PostsController < ApplicationController
  check_permissions if: :some_method

  #...
end

or

class PostsController < ApplicationController
  check_permissions if: ->(controller) { controller.some_method }

  #...
end

or

class PostsController < ApplicationController
  check_permissions unless: some_method

  #...
end

or

class PostsController < ApplicationController
  check_permissions unless: ->(controller) { controller.some_method }

  #...
end

To skip checking permissions for controller, add skip_check_permissions method call:

class PagesController < ApplicationController
  skip_check_permissions

  #...
end

Handling of unpermitted access

If user is not permitted for appropriate action, Cannie::ActionForbidden exception will be raised. It can be handled globally by using rescue_from inside ApplicationController:

class ApplicationController < ActionController::Base
  rescue_from Cannie::ActionForbidden do |exception|
    redirect_to root_path, alert: exception.message
  end
end

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request