0

我正在使用 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 崩溃。任何帮助表示赞赏。

4

1 回答 1

0

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

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

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

于 2013-03-18T20:19:04.627 回答