can-opener

Split up your CanCan Ability by allowing you to easily create abilities in separate classes which you reference in your main ability model. This is mainly useful if you want to break down your abilities into smaller classes for organizational purposes.

Usage

gem install can_opener

Declare ability classes than inherit from CanOpener::Ability, and implement the abilities public instance method. By default, the method will have access to the the local user as per typical use in CanCan.

require 'can_opener'

class AdminAbility < CanOpener::Ability
  def abilities
    if user.admin?
      can :manage, :all
    end
  end
end

class SupportAbility < CanOpener::Ability
  def abilities
    if user.support?
      can :read, :all
      can :write, :all
    end
  end
end

class BannedAbility < CanOpener::Ability
  def abilities
    if user.banned?
      cannot do |action, object_class, object|
        true
      end
    end
  end
end

Then declare your Ability class, but include CanOpener rather than CanCan::Abilities

class Ability
  include CanOpener

  configure_abilities do |c|
    c.add ReaderAbility
    c.add SupportAbility
    c.add AdminAbility, BannedAbility
  end
end

Remember that CanCan processes abilities in a top down fashion, so add your general abilities up top, and then things you want to override everything (like banning a user) at the bottom. You can add line by line or multiple on one line if you wish.

But I want to check the IP Address, Project, etc, in the ability!

Inherit CanOpener::Ability , setup your accessors, use the aditional_ability_arguments class method. Consider the following contrived example:

class TakesIpAddress < CanOpener::Ability
  attr_reader :ip_address      
  aditional_ability_arguments :ip_address
end

class SuperAdmin < TakesIpAddress
  def abilities
    # Wide open, just for testing
    can :manage, :foo
  end
end

class IPBouncer < TakesIpAddress
  def abilities
    cannot :manage, :foo unless ip_address =~ /^192\.168\./
  end
end

class TwoParamAbility
  include CanOpener

  configure_abilities do |c|
    c.add SuperAdmin
    c.add IPBouncer
  end
end

Why?

A couple times when I used CanCan, my abilities definition method got a little long, and I wanted a simple way to break it up for readability.

Todo

  • Perhaps a generator for CanOpener::Ability subclasses.