Project

granted

0.0
No commit activity in last 3 years
No release in over 3 years
Takes care of defining what actions one model is allowed to do with another model.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Project Readme

Dead easy rails permissions Gem Version Build Status Coverage Status

Installation is as easy as 1,2,3:

1.

Add to Gemfile:
gem 'granted'
    

2.

Add to Rakefile:
require 'granted/tasks'
    

3.

Create grants migration:
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
end

How 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
end

It 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
end

First 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 yet

Granting/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
end

It 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.