0.0
No commit activity in last 3 years
No release in over 3 years
A very simple way to manage permissions. Works with any ORM.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
 Project Readme

AbilityList

Simple permissions system as plain old Ruby objects. No fancy integration with ORMs or frameworks.

All of this is just a single Ruby file with less than 50 lines of significant code. Read it now.

Defining abilities

Define the list of abilities a user has by subclassing AbilityList.

Each ability is comprised of a verb (required) and an object (optional). A verb is any symbol, while the object can be a symbol or a class.

class Abilities < AbilityList
  def initialize(user)
    can :view, Video

    if user.admin?
      can :delete, Video
      can :upload, Video
    end

    can :login

    can :view, :admin
  end
end

Then hook it to user by defining an abilities method.

class User < OpenStruct
  include AbilityList::Helpers

  def abilities
    @abilities ||= Abilities.new(self)
  end
end

Checking for abilities

Now you may use can?:

user = User.new
user.can?(:view, Video)
user.can?(:view, Video.find(20))

user.can?(:login)
user.can?(:view, :admin)

The inverse cannot? is also available.

Raising errors

Or you can use authorize!, which is exactly like can? except it raises an AbilityList::Error exception. Perfect for controllers.

user.authorize! :view, Video.find(20)

Custom criteria

You can pass a block to can for custom criteria:

can :view, Video do |video|
  !video.restricted? or user.age > 18
end

You can even use Ruby's &:sym syntax:

cannot :edit, Article, &:published?

# Equivalent to cannot(:edit, Article) { |article| article.published? }

Object types

The method can always accepts at least 2 arguments: a verb and an object.

You can define your permissions by passing a class as the object:

can :view, Video

which makes it possible to check for instances or classes:

user.can?(:view, Video)                 #-> passing a class
user.can?(:view, Video.find(1008))      #-> passing an instance

But this doesn't have to be classes. Just pass anything else, like a symbol:

can :login, :mobile_site

# user.can?(:login, :mobile_site)

Overriding criteria

Criteria are evaluated on a top-down basis, and the ones at the bottom will override the ones on top.

The method cannot is provided to make exceptions to rules.

For example:

# Everyone can edit comments.
can :edit, Comment

# ...but unconfirmed users can't edit their comments.
if user.unconfirmed?
  cannot :edit, Comment
end

# ...but if the comments are really new, they can be edited, even if the user
# hasn't confirmed.
can :edit, Comment { |c| c.created_at < 3.minutes.ago }

The :manage keyword

You can use :manage as the verb to allow any verb.

can :manage, Group

This allows the user to do anything to Group its instances.

user.can?(:delete, Group)       #=> true
user.can?(:create, Group)       #=> true
user.can?(:eviscerate, Group)   #=> true

The :all keyword

You can use :all as the object for any permission. This allows a verb to work on anything.

Don't know why you'll want this, but cancan has it, so:

can :delete, :all

So you can:

user.can?(:delete, Video)     #=> true
user.can?(:delete, Article)   #=> true
user.can?(:delete, Recipe)    #=> true

More examples

See RECIPES.md for some practical examples.

Limitations

AbilityList aims to be extremely lean, and to be as framework- and ORM-agnostic as possible. As such, it doesn't:

  • No explicit integration with Rails controllers.

  • No explicit integration with ActiveRecord (or any other ORM).

  • No explicit provisions for roles.

See RECIPES.md on how to do these things.

Acknowledgements

Heavily inspired by cancan. AbilityList is generally a stripped-down version of cancan with a lot less features (see Limitations) above.

(c) 2013 MIT License.