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)
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.
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
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.
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.
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])
To lookup any permissions that have been assigned to a user/resource, use permissions_for:
current_user.permissions_for(@resource) #=> [:read, :write]
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.
-
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.