Permissable is a project mainly written in Ruby, based on the MIT license.
Basic member/resource permission system for ActiveRecord objects.
= permissable
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.
== Usage
class User < ActiveRecord::Base
has_permissions_for [:section, :category], :to => [:read, :write, :moderate]
end
The permissable method accepts two 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
== Copyright
Copyright (c) 2010 kurb media, llc. See LICENSE for details.