康康:如何排除能力?

时间:2013-03-18 20:04:02

标签: ruby-on-rails-3 cancan

我正在使用cancan为我的应用构建全面的权限系统。我需要能够“排除”某些特定记录,即使在模型上设置了:read或:manage权限,例如。

can :read , User

但我需要排除特定的ID ......类似于:

can :read, User except when id in (1,2,3,.... list_of_excluded_ids)

我尝试通过构建list_of_excluded_ids来完成这项工作,如下所示:

all_ids = User.all
excluded_ids = Excluded.all (This model stores excluded ids)
permitted_id = all_ids - excluded_ids

然后使用此列表,我遍历每个id的设置权限

permitted_ids.each do |permitted_id|
can :read, User, :id => permitted_id
end

当所有ID列表很小时,此方法有效。当列表很大时,它会带来内存错误的mysql,因为它使用OR生成一个非常长的SQL查询,如下所示:

SELECT `users`.* FROM `users` WHERE ((`users`.`id` = 271) OR ((`users`.`id` = 270) OR ((`users`.`id` = 269) OR ((`users`.`id` = 268) OR ((`users`.`id` = 267) OR ((`users`.`id` = 266) OR ((`users`.`id` = 265) OR ((`users`.`id` = 264) OR ((`users`.`id` = 263) OR .....))))))

上面的查询仅作为示例,因为我无法在此处发布整个查询。这个查询变得如此之大,以至于它使mysql崩溃。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

您可以将范围传递给该功能:

can :read, User, User.where(id => permitted_ids) do |u|
  permitted_ids.include? u.id
end

假设permitted_ids是一个数组,这将使用SQL“IN”子句来规范用户的索引操作。对于show动作,CanCan将使用该块,传入正在访问的用户。注意块和范围做同样的事情。这看起来很愚蠢,但CanCan要求您在使用将用于show动作的范围时提供一个块。