Question

My Ability file has

if user.has_role? :admin
  can :manage, :all
else
  can :manage, Company, :id => Company.with_role(:operator, user).pluck(:id)
  ...
end

And my Company Controller index has

def index
@companies = Company.with_role(:operator, current_user)

But when I sign in as a User who operates a company, I cannot access that page. (Even though the Company.with_role(:operator, user) returns a relation in the console!)

Companies have Codes. I am not sure how to write this in cancan:

Company.with_role(:operator, user).map{|o| o.codes}

But the wiki says if I use a block then authorize_resource will not set the instance variable @codes, because it doesn't know which objects belong to the user. So I cannot use:

can :manage, Code =>  do |Code|
    user.has_role? :operator, code.company
end

I am looking for a solution that will let my CodesController do:

def index
if params[:company_id]
  @keywords = Code.where(:company_id => params[:company_id])
end

And otherwise show the user all their Codes across all of the Companies they have the operator role for.

Was it helpful?

Solution

How about:

can :manage, Company do |company|
    user.has_role? :operator, company
end
can :manage, Code do |code|
    user.has_role? :operator, code.company
end

If you didn't use block syntax for the can definition you could use load_and_authorize_resource in your CodesController to filter the index to only those that are accessible to the current user.

Update Because this used the block syntax CanCan can't use determine which objects to load with load_resource (since it wants to use SQL syntax). If you can rewrite it to not use a block syntax then you'll be good. If you have to use the role type logic you can add code similar to the following in your index method in your controller:

@codes = Code.all.select {|code| can?(:manage, code)}

or if you want to bypass the ability in this case for efficiency

@codes = Company.with_role(:operator, @current_user).codes

OTHER TIPS

def index
    if params[:company_id]
      @codes = Company.with_role(:operator, current_user).where(:id => params[:company_id]).map{|o| o.keywords}.flatten
    else
      @codes = Company.with_role(:operator, current_user).map{|operator| operator.keywords}.flatten
    end
  end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top