Role management library with resource scoping
See the codeVery simple Roles library without any authorization enforcement supporting scope on resource object.
Let's see an example:
user.has_role?(:moderator, @forum)
=> false # if user is moderator of another Forum
This library can be easily integrated with any authentication gem (devise, Authlogic, Clearance) and authorization gem* (CanCanCan, authority, Pundit)
*: authorization gem that doesn't provide a role class
Add this to your Gemfile and run the bundle command.
gem "rolify"
First, use the generator to setup Rolify. Role and User class are the default names. However, you can specify any class name you want. For the User class name, you would probably use the one provided by your authentication solution.
If you want to use Mongoid instead of ActiveRecord, just add --orm=mongoid argument, and skip to step #3.
rails g rolify Role User
NB for versions of Rolify prior to 3.3, use:
rails g rolify:role Role User
The generator will create your Role model, add a migration file, and update your User class with new class methods.
Let's migrate!
rake db:migrate
This gem adds the rolify method to your User class. You can also specify optional callbacks on the User class for when roles are added or removed:
class User < ActiveRecord::Base
rolify :before_add => :before_add_method
def before_add_method(role)
# do something before it gets added
end
end
The rolify method accepts the following callback options:
before_addafter_addbefore_removeafter_removeMongoid callbacks are also supported and works the same way.
The rolify method also accepts the inverse_of option if you need to disambiguate the relationship.
In the resource models you want to apply roles on, just add resourcify method.
For example, on this ActiveRecord class:
class Forum < ActiveRecord::Base
resourcify
end
class User < ActiveRecord::Base
after_create :assign_default_role
def assign_default_role
self.add_role(:newuser) if self.roles.blank?
end
end
To define a global role:
user = User.find(1)
user.add_role :admin
To define a role scoped to a resource instance:
user = User.find(2)
user.add_role :moderator, Forum.first
To define a role scoped to a resource class:
user = User.find(3)
user.add_role :moderator, Forum
Remove role:
user = User.find(3)
user.remove_role :moderator
That's it!
To check if a user has a global role:
user = User.find(1)
user.add_role :admin # sets a global role
user.has_role? :admin
=> true
To check if a user has a role scoped to a resource instance:
user = User.find(2)
user.add_role :moderator, Forum.first # sets a role scoped to a resource instance
user.has_role? :moderator, Forum.first
=> true
user.has_role? :moderator, Forum.last
=> false
To check if a user has a role scoped to a resource class:
user = User.find(3)
user.add_role :moderator, Forum # sets a role scoped to a resource class
user.has_role? :moderator, Forum
=> true
user.has_role? :moderator, Forum.first
=> true
user.has_role? :moderator, Forum.last
=> true
A global role overrides resource role request:
user = User.find(4)
user.add_role :moderator # sets a global role
user.has_role? :moderator, Forum.first
=> true
user.has_role? :moderator, Forum.last
=> true
To check if a user has the exact role scoped to a resource class:
user = User.find(5)
user.add_role :moderator # sets a global role
user.has_role? :moderator, Forum.first
=> true
user.has_strict_role? :moderator, Forum.last
=> false
Starting from rolify 3.0, you can search roles on instance level or class level resources.
forum = Forum.first
forum.roles
# => [ list of roles that are only bound to forum instance ]
forum.applied_roles
# => [ list of roles bound to forum instance and to the Forum class ]
Forum.with_role(:admin)
# => [ list of Forum instances that have role "admin" bound to them ]
Forum.without_role(:admin)
# => [ list of Forum instances that do NOT have role "admin" bound to them ]
Forum.with_role(:admin, current_user)
# => [ list of Forum instances that have role "admin" bound to them and belong to current_user roles ]
Forum.with_roles([:admin, :user], current_user)
# => [ list of Forum instances that have role "admin" or "user" bound to them and belong to current_user roles ]
User.with_any_role(:user, :admin)
# => [ list of User instances that have role "admin" or "user" bound to them ]
User.with_role(:site_admin, current_site)
# => [ list of User instances that have a scoped role of "site_admin" to a site instance ]
User.with_role(:site_admin, :any)
# => [ list of User instances that have a scoped role of "site_admin" for any site instances ]
User.with_all_roles(:site_admin, :admin)
# => [ list of User instances that have a role of "site_admin" and a role of "admin" bound to it ]
Forum.find_roles
# => [ list of roles that are bound to any Forum instance or to the Forum class ]
Forum.find_roles(:admin)
# => [ list of roles that are bound to any Forum instance or to the Forum class, with "admin" as a role name ]
Forum.find_roles(:admin, current_user)
# => [ list of roles that are bound to any Forum instance, or to the Forum class with "admin" as a role name, and belongs to current_user ]
class User < ActiveRecord::Base
rolify strict: true
end
@user = User.first
@user.add_role(:forum, Forum)
@user.add_role(:forum, Forum.first)
@user.has_role?(:forum, Forum) #=> true
@user.has_role?(:forum, Forum.first) #=> true
@user.has_role?(:forum, Forum.last) #=> false
I.e. you get true only on a role that you manually add.
@user.add_role :admin, Forum
@user.add_role :member, Forum
users = User.with_role(:admin, Forum).preload(:roles)
users.each do |user|
user.has_cached_role?(:member, Forum) # no extra queries
end
This method should be used with caution. If you don't preload the roles, the has_cached_role? might return false. In the above example, it would return false for @user.has_cached_role?(:member, Forum), because User.with_role(:admin, Forum) will load only the :admin roles.
Please read the upgrade instructions.
If you have any issue or feature request with/for rolify, please create an new issue on GitHub specifying the ruby runtime, rails and rolify versions you're using and the gems listed in your Gemfile, or fork the project and send a pull request.
To get the specs running you should call bundle and then rake. See the spec/README for more information.
Overall
Maintained
Code review
RubyGems
Latest release
Releases this year
2,973 followers · starred Jun 2015
544 followers · starred Mar 2019
119 followers · starred Jun 2011
58 followers · starred Nov 2015
Role management library with resource scoping
See the codeVery simple Roles library without any authorization enforcement supporting scope on resource object.
Let's see an example:
user.has_role?(:moderator, @forum)
=> false # if user is moderator of another Forum
This library can be easily integrated with any authentication gem (devise, Authlogic, Clearance) and authorization gem* (CanCanCan, authority, Pundit)
*: authorization gem that doesn't provide a role class
Add this to your Gemfile and run the bundle command.
gem "rolify"
First, use the generator to setup Rolify. Role and User class are the default names. However, you can specify any class name you want. For the User class name, you would probably use the one provided by your authentication solution.
If you want to use Mongoid instead of ActiveRecord, just add --orm=mongoid argument, and skip to step #3.
rails g rolify Role User
NB for versions of Rolify prior to 3.3, use:
rails g rolify:role Role User
The generator will create your Role model, add a migration file, and update your User class with new class methods.
Let's migrate!
rake db:migrate
This gem adds the rolify method to your User class. You can also specify optional callbacks on the User class for when roles are added or removed:
class User < ActiveRecord::Base
rolify :before_add => :before_add_method
def before_add_method(role)
# do something before it gets added
end
end
The rolify method accepts the following callback options:
before_addafter_addbefore_removeafter_removeMongoid callbacks are also supported and works the same way.
The rolify method also accepts the inverse_of option if you need to disambiguate the relationship.
In the resource models you want to apply roles on, just add resourcify method.
For example, on this ActiveRecord class:
class Forum < ActiveRecord::Base
resourcify
end
class User < ActiveRecord::Base
after_create :assign_default_role
def assign_default_role
self.add_role(:newuser) if self.roles.blank?
end
end
To define a global role:
user = User.find(1)
user.add_role :admin
To define a role scoped to a resource instance:
user = User.find(2)
user.add_role :moderator, Forum.first
To define a role scoped to a resource class:
user = User.find(3)
user.add_role :moderator, Forum
Remove role:
user = User.find(3)
user.remove_role :moderator
That's it!
To check if a user has a global role:
user = User.find(1)
user.add_role :admin # sets a global role
user.has_role? :admin
=> true
To check if a user has a role scoped to a resource instance:
user = User.find(2)
user.add_role :moderator, Forum.first # sets a role scoped to a resource instance
user.has_role? :moderator, Forum.first
=> true
user.has_role? :moderator, Forum.last
=> false
To check if a user has a role scoped to a resource class:
user = User.find(3)
user.add_role :moderator, Forum # sets a role scoped to a resource class
user.has_role? :moderator, Forum
=> true
user.has_role? :moderator, Forum.first
=> true
user.has_role? :moderator, Forum.last
=> true
A global role overrides resource role request:
user = User.find(4)
user.add_role :moderator # sets a global role
user.has_role? :moderator, Forum.first
=> true
user.has_role? :moderator, Forum.last
=> true
To check if a user has the exact role scoped to a resource class:
user = User.find(5)
user.add_role :moderator # sets a global role
user.has_role? :moderator, Forum.first
=> true
user.has_strict_role? :moderator, Forum.last
=> false
Starting from rolify 3.0, you can search roles on instance level or class level resources.
forum = Forum.first
forum.roles
# => [ list of roles that are only bound to forum instance ]
forum.applied_roles
# => [ list of roles bound to forum instance and to the Forum class ]
Forum.with_role(:admin)
# => [ list of Forum instances that have role "admin" bound to them ]
Forum.without_role(:admin)
# => [ list of Forum instances that do NOT have role "admin" bound to them ]
Forum.with_role(:admin, current_user)
# => [ list of Forum instances that have role "admin" bound to them and belong to current_user roles ]
Forum.with_roles([:admin, :user], current_user)
# => [ list of Forum instances that have role "admin" or "user" bound to them and belong to current_user roles ]
User.with_any_role(:user, :admin)
# => [ list of User instances that have role "admin" or "user" bound to them ]
User.with_role(:site_admin, current_site)
# => [ list of User instances that have a scoped role of "site_admin" to a site instance ]
User.with_role(:site_admin, :any)
# => [ list of User instances that have a scoped role of "site_admin" for any site instances ]
User.with_all_roles(:site_admin, :admin)
# => [ list of User instances that have a role of "site_admin" and a role of "admin" bound to it ]
Forum.find_roles
# => [ list of roles that are bound to any Forum instance or to the Forum class ]
Forum.find_roles(:admin)
# => [ list of roles that are bound to any Forum instance or to the Forum class, with "admin" as a role name ]
Forum.find_roles(:admin, current_user)
# => [ list of roles that are bound to any Forum instance, or to the Forum class with "admin" as a role name, and belongs to current_user ]
class User < ActiveRecord::Base
rolify strict: true
end
@user = User.first
@user.add_role(:forum, Forum)
@user.add_role(:forum, Forum.first)
@user.has_role?(:forum, Forum) #=> true
@user.has_role?(:forum, Forum.first) #=> true
@user.has_role?(:forum, Forum.last) #=> false
I.e. you get true only on a role that you manually add.
@user.add_role :admin, Forum
@user.add_role :member, Forum
users = User.with_role(:admin, Forum).preload(:roles)
users.each do |user|
user.has_cached_role?(:member, Forum) # no extra queries
end
This method should be used with caution. If you don't preload the roles, the has_cached_role? might return false. In the above example, it would return false for @user.has_cached_role?(:member, Forum), because User.with_role(:admin, Forum) will load only the :admin roles.
Please read the upgrade instructions.
If you have any issue or feature request with/for rolify, please create an new issue on GitHub specifying the ruby runtime, rails and rolify versions you're using and the gems listed in your Gemfile, or fork the project and send a pull request.
To get the specs running you should call bundle and then rake. See the spec/README for more information.
Overall
Maintained
Code review
RubyGems
Latest release
Releases this year
2,973 followers · starred Jun 2015
544 followers · starred Mar 2019
119 followers · starred Jun 2011
58 followers · starred Nov 2015