Nathan Pena Nathan Pena - 1 year ago 116
Ruby Question

Assign Conflicting CanCan Roles

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
if user.role?(y)
cannot :manage, Post
can :manage, Article

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.

Answer Source


if user.role?(x)
  can :manage, Post
if user.role?(y)
  can :manage, Article

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

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

    if user.role?(:reader)
      can :read, Post

class Post

class User
  attr_reader :name
  def initialize(name, *roles)
    @name = name
    @roles = roles

  def role?(role)

admin ='admin', :reader, :editor)
user ='user', :reader)
editor ='editor', :editor)

admin_ability =
user_ability =
editor_ability =

def output(ability, permission)
  puts "#{} can #{permission} Post: #{ability.can?(permission, Post)}"

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download