使用角色和组模型在更复杂的环境中定义能力

时间:2011-08-20 09:15:09

标签: ruby-on-rails permissions roles cancan

在我的rails应用程序中(我使用设计和cancan),每个(注册)用户属于完全一个角色('管理员'或'用户')但至少 一组(类似'家庭','朋友','同事')。在运行时,当创建新文件夹(见下文)时,可以设置与一个或多个组的habtm关系,该关系定义谁可以访问该文件夹。完全选择 no 组应该会生成一个全球可访问的文件夹(即用户无需登录即可访问这些文件夹)。但是现在,我还不知道如何在我的ability.rb中定义这样的全球可访问文件夹,因为我不知道如何定义“可以读取没有与之关联的组的文件夹”。

我的app/models/ability.rb的相关片段如下所示:

user ||= User.new
if user.role? :Administrator
  can :manage, :all
elsif user.role? :Users
  # user should only be able to read folders, whose associated groups they are member of
  can :read, Folder, :groups => { :id => user.group_ids }
else
  # here goes the world-wide-accessible-folders part, I guess
  # but I don't know how to define it:
  ## can :read, Folder, :groups => { 0 } ???
end

我的app/controllers/folders_controller.rb的相关片段如下所示:

class FoldersController < ApplicationController
  before_filter :authenticate_user!
  load_and_authorize_resource

有人能给我一个暗示吗?

1 个答案:

答案 0 :(得分:4)

前几天我遇到了同样的问题。我在阅读了CanCan自述文件后想出了解决方案,如果你还没有,你应该这样做。

您可以在此处查看我的解决方案:Context aware authorization using CanCan

为了给出更具体针对您的用例的答案,请执行以下操作:

在你的应用程序控制器中,你需要定义一些能够挑选你能力的逻辑。

class ApplicationController < ActionController::Base
  check_authorization

  def current_ability
    if <no group selected logic> # Maybe: params[:controller] == 'groups'
      @current_ability = NoGroupSelectedAbility.new(current_user)
    else
      @current_ability = GroupSelectedAbility.new(current_user)
    end
  end

  # Application Controller Logic Below
end

然后,您需要在app / models /文件夹中创建一项新能力(或多种能力)。你也可以做这样的酷事:

if request.path_parameters[:controller] == groups
  @current_ability = GroupsAbility.new(current_group_relation)
end 

其中current_group_relation在app / controllers / groups_controller.rb中定义。这将为您提供特定控制器的特定功能。请记住,父类可以在Ruby中调用子类中的方法。您可以在控制器中定义一个方法,并从ApplicationController中调用它,只要您确定当前正在使用哪个控制器来处理请求。

希望有所帮助。

编辑:我想向您展示自定义功能的样子。

# File path: app/models/group_ability.rb
class GroupsAbility
  include CanCan::Ability

  # This can take in whatever you want, you decide what to argument to 
  # use in your Application Controller
  def initialize(group_relation)
    group_relation ||= GroupRelation.new

    if group_relation.id.nil?
      # User does not have a relation to a group
      can :read, all
    elsif group_relation.moderator?
      # Allow a mod to manage all group relations associated with the mod's group.
      can :manage, :all, :id => group_relation.group.id
    end
  end
end