Installation is as easy as 1,2,3:
1.gem 'granted'
|
2.require 'granted/tasks'
|
3.rake granted:create_migration rake db:migrate |
This gem lets you define arbitrary permissions on a per object level (as opposed to roles). They are implemented purely as active record associations and hence easy to understand. Check out this readme on how to grant read/write permissions on individual documents to individual users. This is a moviepilot.com project licensed MIT. And now, code:
# Let's grant a user access to a document
user.grant(:read).on(document)
# Let's revoke a user's write access to a document
user.revoke(:grant).from(document)
# We can also do it rails association style
document.read_users << user
# Let's count all documents a user has read access to
user.readable_documents.count
# Let's count all documents a user has any access to
user.all_documents.count
# List the rights a user has to a certain document
user.grants_for(document)
=> [:read, :write]
# Define the things we took for granted (scuse me) above
class Document
include Granted::ForGranted
# Creates associations and grant/revoke methods
grantable :read, :write, :destroy, to: User
endHow does it work
When creating the migration with rake granted:create_migration,
this gem will add a migration to your rails app that creates a
grants table when you run it. This is a polymorphic model sitting
between a grantee (e.g. User and a subject (e.g. Document).
It has only one attribute, and that is the right that it gives the
grantee to do with the subject.
What does this code do?
class Document < ActiveRecord::Base
include Granted::ForGranted
grantable :read, :write, to: User
endIt does that:
class Granted::WriteGrant < Granted::Grant; end
class Granted::ReadGrant < Granted::Grant; end
class Document < ActiveRecord::Base
has_many :grants, as: :subject, class_name: 'Granted::Grant', dependent: :destroy
has_many :write_grants, as: :subject, class_name: 'Granted::WriteGrant'
has_many :read_grants, as: :subject, class_name: 'Granted::ReadGrant'
has_many :write_users, source: :grantee, source_type: 'User', through: :write_grants
has_many :read_users, source: :grantee, source_type: 'User', through: :read_grants
has_many :all_users, source: :grantee, source_type: 'User', through: :grants, uniq: true
attr_accessible :write_users_attributes, :read_users_attributes
accepts_nested_attributes_for :write_users, :read_users
end
class User < ActiveRecord::Base
has_many :grants, as: :grantee, class_name: 'Granted::Grant', dependent: :destroy
has_many :write_grants, as: :grantee, class_name: 'Granted::WriteGrant'
has_many :read_grants, as: :grantee, class_name: 'Granted::ReadGrant'
has_many :writeable_documents, source: :subject, source_type: 'Document', through: :write_grants
has_many :readable_documents, source: :subject, source_type: 'Document', through: :read_grants
has_many :all_documents, source: :subject, source_type: 'Document', through: :grants, uniq: true
# It does not do this yet, but hopefully soon :)
# attr_accessible :writeable_documents_attributes, :readable_documents_attributes
# accepts_nested_attributes_for :writeable_documents, :readable_documents
endFirst it creates STI classes that inherit from Granted::Grant, one for
each right you defined as grantable (e.g. ReadGrant, WriteGrant).
It then creates the appropriate has_many relations to both User and
Document, so that they can be connected with a Grant instance.
So you have all the access control available via normal active record
associations (reading and writing).
PSA: You can only grant/revoke rights via the grantee side at the moment, the other direction is not yet implemented:
document.read_users << my_user # Works
my_user.readable_documents << document # Doesn't work yetGranting/revoking rights
So now that you know how querying grants/rights work, you might wonder how you give or revoke certain access rights to a user and a document. Consider this familiar snippet of code:
class Document < ActiveRecord::Base
include Granted::ForGranted
grantable :read, :write, to: User
endIt does not only create the associations, it also creates the grant
and revoke methods on User and Document. They return a convenient
little object (Grant::Granter, if you're curious).
You can grant/revoke access rights using Users or Documents as a starting
point, it's all the same:
# Both ways to grant are identical
my_user.grant(:read).on(my_document)
my_document.grant(:read).to(my_user)
# Both ways to revoke are identical
my_user.revoke(:read).on(my_document)
my_document.revoke(:read).from(my_user)
# Clever: even weird grammatic yields identic results
my_user.on(my_document).revoke(:read)
my_document.from(:my_user).revoke(:read)
# This is what the grant/revoke methods do:
Granted::Granter.new.grant(:read).on(my_document).to(my_user)
Granted::Granter.new.revoke(:read).on(my_document).from(my_user)Interedasting things
You can use arrays or single objects in grantable both as access rights
and grantees:
class Document < ActiveRecord::Base
include Granted::ForGranted
grantable :read, to: [User, Editor]
grantable :update, :destroy, to: [Editor]
end
my_document.grant(:read, :write).to(my_user)That is all.