Basic member/resource permission system for ActiveRecord objects.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
.document Initial commit to permissable. Jul 24, 2010
README.rdoc Updated rdoc Oct 3, 2010
init.rb Completed basic permission functionality Jul 25, 2010



Permissable creates the ability to add a permissions system to “resources” based on a “member”. It allows you to define a member using the permissable method:

class User < ActiveRecord::Base has_permissions_for [:section, :category], :to => [:read, :write, :moderate] end

Permissable uses a single “permissions” table (and subsuquently a Permission model), with a polymorphic relationship between both the member and the resource.


class User < ActiveRecord::Base has_permissions_for [:section, :category], :to => [:read, :write, :moderate] end

The permissable method accepts two options:

  • method: The permission you want to assign (read, write, moderate, etc)

  • options: A hash of options.

The only required option is the :to key, which defines a number of permisssions to assign to the speficied resource(s)

Once permissions have been assigned, use the can? method to check for them:

# current_user is the currently logged in user # @resource is a loaded resource model of any type current_user.can?(:read, @resource)

Setting Permissions via Association

Permissable also allows you to specify permissions via an association. For instance say your User has_many roles, and you would like the permissions to be based on a particular user's roles. To do this, add the :through option when setting permissions:

:through => :roles When permissable does permission lookups on any of the resources specified in has_permissions_for it will use the assocation to define them. Instead of looking up User.permissions, it will now lookup user.roles.permissions.

Always allowing specific members

If you would like can? to always pass for a particular member, use the :allow_with option with has_permissions_for. The allow_with option accepts a method name within your member model that will be called prior to checking permissions from the database.

class User < ActiveRecord::Base has_permissions_for [:section, :category], :to => [:read, :write, :moderate], :allow_with => :is_admin? def is_admin? // your logic here. If this resolves to true… can? will also be true. end end

Chaining Permissions

If you want your permissions to have a heirarchy, use the :chain option. For example, say you have three permission types: read, write, and moderate. In this instance, moderators should also be able to read and write a resource, and members who can write should also be able to read the resource. To do this, add this chain when calling has_permissions_for:

class User < ActiveRecord::Base has_permissions_for [:resource], :to => [:read, :write, :moderate], :chain => { :moderate => [:read, :write], :write => [:read] } end Now calling can?(:read, @resource) will evaluate to true when permissions exist for reading or writing, and can?(:read, @resource) will evaluate to true when permissions exist at least to write.

Eager Loading

More than likely you want to eager-load permissions for each user. To do this, simply call load_permissions! on that user.

# current_user returns the currently logged in user current_user.load_permissions! All requests for can? will now use a permissions cache.

Creating / Assigning new Permissions

To give a user permission to access a resource, use the can! method. Calling this method creates and saves the new permission.

# current_user returns the currently logged in user # @resource is a loaded resource of any type/class/format # current_user.can?(:write, @resource) #=> false current_user.can!(:write, @resource) # current_user.can?(:write, @resource) #=> true can! can accept arrays or single values for both the permission to assign, as well as the resources to assign them to:

current_user.can!([:read, :write, :moderate], [@resource1, @resource2])

Looking up existing permissions

To lookup any permissions that have been assigned to a user/resource, use permissions_for:

current_user.permissions_for(@resource) #=> [:read, :write]

Note / Todo

At this point there aren't any test suites, as this gem was originally written/extracted from a project we were working on. Everything passes in the project itself, and this gem is being used in production, but tests still need to be integrated into the gem itself. Feel free to contribute any.

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don't break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)

  • Send me a pull request. Bonus points for topic branches.


Copyright © 2010 kurb media, llc. See LICENSE for details.