How to use cancan to authorize an array of resources?

I have an unresponsive controller that I'm trying to use cancan authorize! method for applying permissions.

I have a delete_multiple action that starts like this

def delete_multiple @invoices = apparent_user.invoices.find(params[:invoice_ids]) 

I want to check if the user has the right to delete all these invoices before continuing. If i use

 authorize! :delete_multiple, @invoices 

permission denied. My .rb ability includes the following

 if user.admin? can :manage, :all elsif user.approved_user? can [:read, :update, :destroy, :delete_multiple], Invoice, :user_id => user.id end 

Is this a matter of looping in my array and calling authorization separately or is there a smarter way to do something? I'm starting to feel that authorization will be easier manually than using cancan for a complex non-recovery controller (although I have many other soothing controllers in my application where it works great).

+4
source share
2 answers

A little late, but you can write it in your class of features

 can :delete_multiple, Array do |arr| arr.inject(true){|r, el| r && can?(:delete, el)} end 

EDIT

This can also be written as:

 can :delete_multiple, Array do |arr| arr.all? { |el| can?(:delete, el) } end 
+10
source

It seems that authorize! only works with one instance, not an array. Here's how I got around this with Rails 3.2.3 and CanCan 1.6.7.

The main idea is to count the total records that the user is trying to delete, count the accessible_by (current_ability, :destroy) records, and then compare the counts.

If you need an array of records that the user is allowed to destroy, you can use the array returned by accessible_by (current_ability, :destroy) . However, I use destroy_all , which works directly on the model, so I ended up with this solution to calculate the quantity and compare.

You should check the development log to see how the two SELECT COUNT look: the second should add WHERE phrases for the authorization restrictions imposed by CanCan.

My example deals with deleting multiple messages.

ability.rb

 if user.role_atleast? :standard_user # Delete messages that user owns can [:destroy, :multidestroy], Message, :owner_id => user.id end 

messages_controller.rb

 # Suppress load_and_authorize_resource for actions that need special handling: load_and_authorize_resource :except => :multidestroy # Bypass CanCan ApplicationController#check_authorization requirement: skip_authorization_check :only => :multidestroy ... def multidestroy # Destroy multiple records (selected via check boxes) with one action. @messages = Message.scoped_by_id(params[:message_ids]) # if check box checked to_destroy_count = @messages.size @messages = @messages.accessible_by(current_ability, :destroy) # can? destroy authorized_count = @messages.size if to_destroy_count != authorized_count raise CanCan::AccessDenied.new # rescue should redirect and display message else # user is authorized to destroy all selected records if to_destroy_count > 0 Message.destroy_all :id => params[:message_ids] flash[:success] = "Permanently deleted messages" end redirect_to :back end end 
+1
source

Source: https://habr.com/ru/post/1345388/


All Articles