如何使用cancan来授权一系列资源?
我有一个非宁静的控制器,我正在尝试使用cancan授权! 应用权限的方法。
我有一个像这样开始的delete_multiple动作
def delete_multiple @invoices = apparent_user.invoices.find(params[:invoice_ids])
我想在继续操作之前检查用户是否有权删除所有这些发票。 如果我使用
authorize! :delete_multiple, @invoices
许可被拒绝。 我的能力.rb包括以下内容
if user.admin? can :manage, :all elsif user.approved_user? can [:read, :update, :destroy, :delete_multiple], Invoice, :user_id => user.id end
这是循环遍历我的数组并单独调用授权还是有更聪明的做事方式? 我开始觉得做授权会比使用cancan用于复杂的非静态控制器更容易手动(尽管我的应用程序中有很多其他的安静控制器,它工作得很好)。
在这里稍晚,但你可以在你的能力课上写这个
can :delete_multiple, Array do |arr| arr.inject(true){|r, el| r && can?(:delete, el)} end
编辑
这可以写成:
can :delete_multiple, Array do |arr| arr.all? { |el| can?(:delete, el) } end
似乎authorize!
仅适用于单个实例,而不适用于数组。 以下是我使用Rails 3.2.3和CanCan 1.6.7解决这个问题的方法。
基本思想是计算用户试图删除的总记录数,计算accessible_by (current_ability, :destroy)
,然后比较计数。
如果您只想要用户有权销毁的记录数组,则可以使用accessible_by (current_ability, :destroy)
返回的数组。 但是我正在使用destroy_all
,它直接在模型上运行,所以我最终得到了这个计数和比较解决方案。
值得检查开发日志以查看两个SELECT COUNT
语句的外观:第二个应该为CanCan强加的授权限制添加WHERE
短语。
我的例子涉及删除多条消息。
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's 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