I am using the CanCan Gem and would like to assign a User two roles which conflict. I need a User to have two roles, one is the x role and the other is the y role. Role x allows users to create posts but not create articles. Role y allows users to create articles but not create posts.
My ability.rb file is like the following:
if user.role?(x)
can :manage, Post
cannot :manage, Article
end
if user.role?(y)
cannot :manage, Post
can :manage, Article
end
Currently if I assign a User both roles, the permissions for role Y will override the permissions for role x. I would like to allow Admins to stack roles so that if I want to add roles x and y to a User, that User will be able to manage Posts and Articles. So if the role has a can and another role has a cannot, the can permission overrides.
Shouldn't
if user.role?(x)
can :manage, Post
end
if user.role?(y)
can :manage, Article
end
be enough?
cannot
just removes previously granted permissions. But if you do not grant them, then you do not need to remove them.
See also https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence
Here is a running example:
require 'cancan'
class Ability
include CanCan::Ability
attr_reader :user
def initialize(user)
@user = user
if user.role?(:editor)
can :edit, Post
end
if user.role?(:reader)
can :read, Post
end
end
end
class Post
end
class User
attr_reader :name
def initialize(name, *roles)
@name = name
@roles = roles
end
def role?(role)
@roles.include?(role)
end
end
admin = User.new('admin', :reader, :editor)
user = User.new('user', :reader)
editor = User.new('editor', :editor)
admin_ability = Ability.new(admin)
user_ability = Ability.new(user)
editor_ability = Ability.new(editor)
def output(ability, permission)
puts "#{ability.user.name} can #{permission} Post: #{ability.can?(permission, Post)}"
end
output(admin_ability, :edit)
output(user_ability, :edit)
output(editor_ability, :edit)
puts "--"
output(admin_ability, :read)
output(user_ability, :read)
output(editor_ability, :read)
The default is to NOT HAVE a permission. So if you only work in "additive" mode where you add permissions if a user has roles, you will never need to remove one of them.
:manage
is the same as [:create, :edit, :update, :new, :destroy, :index, :show]
and is only there for convenience. If you only want to add 6 of those permissions, you can add all 7 and then remove 1. But other than that I don't think you'll need cannot
for your example.