Reputation: 3173
I'm using CanCan in a project to manage different role level on each entity for each project. I'm doing this:
# encoding: utf-8
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.is_admin == true
can :manage, :all
else
can :read, :all
Project.all.each do |project|
current_role_name = user.roles.find_by_project_id(project.id).role_name.name
if current_role_name.eql?'Auteur senior'
can :manage, [Project, Introduction, Abstract, Text, Conclusion, Asset, Attachment], :project_id => project.id
elsif current_role_name.eql?'Auteur junior'
can :manage, [Introduction, Abstract, Attachment], :project_id => project.id
can :update, Text, :project_id => project.id, :user_level => current_role_name
can :manage, [Asset], :project_id => project.id, :user_level => current_role_name
elsif current_role_name.eql?'Équipe phylogéniste'
can :manage, [Attachment], :project_id => project.id
can :manage, [Text, Asset], :project_id => project.id, :user_level => current_role_name
end
end
end
end
end
It works when I check the user role_name but after when I want to use condition like this:
can :update, Text, :project_id => project.id, :user_level => current_role_name
The condition doesn't have any effect. How can I make it work?
Upvotes: 0
Views: 1807
Reputation: 574
The authorize_resource
method calls authorize!
on the class unless it is passed an instance. Without using load_resource
or load_and_authorize_resource
, you're passing nil to the authorize_resource
before_filter.
Example from the CanCan documentation:
#authorize_resource(*args) ⇒ Object
authorize!(params[:action].to_sym, @article || Article)
If you want to load records from the database with your own method (instead of CanCan's load_resource
) and have more control, then you can create your own method like load_thing
and call it with prepend_before_filter :load_thing
. This will load the record into the instance variable before authorize_resource
is called, ensuring the instance variable isn't nil and the rules specified in the ability file are checked.
Upvotes: 0
Reputation: 3173
I finally found the solution :
In concerned controller I replaced authorize_resource by load_and_authorize_resource and that's it.
Upvotes: 1
Reputation: 11
What I usely do is:
1- defining roles in my User class and affect them to users.
class User
# CanCan roles ( see Users::Ability)
ROLES = %w[auteur_senior auteur_junior]
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end
def roles
ROLES.reject do |r|
((roles_mask || 0) & 2**ROLES.index(r)).zero?
end
end
def is?(role)
roles.include?(role.to_s)
end
# define all bollean set/get methods for roles
ROLES.each do |r|
define_method "is_#{r}" do
self.roles += [r]
self
end
define_method "is_#{r}?" do
roles.include?(r)
self
end
end
end
2-In the ability I affect the capabilities of each roles
class Ability
include CanCan::Ability
def initialize(user)
@user = user || User.new # for guest
@user.roles.each { |role| send(role) }
end
def auteur_junior
can :manage, [Introduction, Abstract, Attachment], :project_id => project.id
can :update, Text, :project_id => project.id, :user_level => current_role_name
can :manage, [Asset], :project_id => project.id, :user_level => current_role_name
end
def auteur_scenior
can :manage, [Project, Introduction, Abstract, Text, Conclusion, Asset, Attachment], :project_id => project.id
end
end
Upvotes: 1