如何使用cancan对一系列资源进行授权?

发布于 2024-10-27 03:15:55 字数 612 浏览 1 评论 0原文

我有一个非静态控制器,我正在尝试使用 cancan 授权!方法来应用权限。

我有一个 delete_multiple 操作,其启动方式如下,

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

我想在继续之前检查用户是否有权删除所有这些发票。如果我使用

authorize! :delete_multiple, @invoices

许可被拒绝。我的ability.rb 包括以下内容

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

这是循环遍历我的数组并单独调用授权的问题还是有更智能的处理方法?我开始觉得手动授权比使用 cancan 来处理复杂的非静态控制器更容易(尽管我的应用程序中有很多其他静态控制器,效果很好)。

I have a non-restful controller that I am trying to use the cancan authorize! method to apply permissions to.

I have a delete_multiple action that starts like so

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

I want to check that the user has permission to delete all of these invoices before proceeding. If I use

authorize! :delete_multiple, @invoices

permission is refused. My ability.rb 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 it a matter of looping through my array and calling authorize individually or is there a smarter way of doing things? I'm starting to feel like doing authorizations would be easier manually than by using cancan for a complicated non-restful controller (although I have plenty of other restful controllers in my app where it works great).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

來不及說愛妳 2024-11-03 03:15:55

这里有点晚了,但你可以在你的能力类中写这个

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

A little late in here but you can write this in your ability class

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

EDIT

This can be written also as:

can :delete_multiple, Array do |arr|
  arr.all? { |el| can?(:delete, el) }
end
月牙弯弯 2024-11-03 03:15:55

似乎 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 短语。

我的示例涉及删除多条消息。

能力.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 

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

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

If you just wanted an array of records that the user is authorized to destroy, you could use the array returned by accessible_by (current_ability, :destroy). However I'm using destroy_all, which works directly on the model, so I wound up with this count-and-compare solution.

It's worthwhile to check the development log to see how the two SELECT COUNT statements look: the second one 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'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 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文