能否使用cancan两个权限类?

6
我正在使用rails 3.0.9,cancan 1.6.7和devise 1.4.8。
我使用两个devise模型(User和Admin)来进行不同的登录和注册流程。
因此,我想根据已登录用户(资源)分配能力,因为有70多个模型,只有10个模型适用于两种类型的用户(这里有50多个模型和视图只由管理员用户使用)。
我想要实现两个Ability类(UserAbility和AdminAbility),并将devise帮助方法current_user/current_admin传递给UserAbility/AdminAbility。
示例:
在ApplicationController.rb文件中:
    def current_ability
        if current_user
            @current_ability = UserAbility.new(current_user)
        elsif current_admin
            @current_ability = AdminAbility.new(current_admin)
        end
    end

从上述我的问题中,

  1. cancan是否支持多个能力类,如果支持,如何创建它,因为我尝试过

    rails g cancan:user_ability

    但是我得到了错误:无法找到生成器cancan:user_ability

  2. 如何为已登录的用户/管理员选择适当的Ability类。

  3. 如果一个控制器既可以被用户又可以被管理员访问,那么如何获取当前已登录的用户/管理员对象

还有其他解决方法吗?

请任何人帮忙解决这个问题

4个回答

14

尽管如此,如果您喜欢的话,您可以直接使用多个能力模型:

class UserAbility
  include CanCan::Ability

  def initialize(user)
    can :read, :all
  end
end

class AdminAbility
  include CanCan::Ability

  def initialize(admin)
    can :manage, :all
  end
end

class ApplicationController < ActionController::Base
  # overriding CanCan::ControllerAdditions
  def current_ability
    if current_account.kind_of?(AdminUser)
      @current_ability ||= AdminAbility.new(current_account)
    else
      @current_ability ||= UserAbility.new(current_account)
    end
  end
end

是的,我只尝试过这个,但我尝试了很多次创建另一个cancan Ability类,但我做不到(可能是因为我不知道正确的语法)。 - nishanthan
你不需要一个生成器 -- 只需在 app/models 中创建一个新文件,并 include CanCan::Ability - willglynn

7

您不需要为此使用多个能力类:

class Ability
  include CanCan::Ability

  def initialize(user_or_admin)
    user_or_admin ||= User.new

    common_rules(user_or_admin)

    if user_or_admin.kind_of? Admin
      admin_rules(user_or_admin)
    else
      user_rules(user_or_admin)
    end
  end

  def common_rules(user_or_admin)
    # can :verb, :noun
  end

  def admin_rules(admin)
    can :manage, :all
  end

  def user_rules(user)
    can :read, :all
  end
end

CanCan最终将使用Ability.new()调用任一模型,但这完全没问题,因为您可以检查接收到的对象类型。当然,如果你喜欢,你可以委托给其他对象;这仅仅是Ruby。


谢谢@willglynn,我会去尝试的。请问,在视图中是否有可能每次调用一个返回当前登录用户/管理员对象的辅助方法,或者还有其他获取此对象的方法? - nishanthan
这取决于你的应用程序的其余部分。这当然是可能的,但我无法告诉你如何做。 - willglynn
高雅的解决方案。整洁。 - Rafael Oliveira
1
如果你的单个 ability.rb 文件变得难以处理,请参考这里将它们分离成单独的文件:http://stackoverflow.com/questions/7738376/cancan-abilities-in-separate-file/25723811?stw=2#25723811 - Joshua Pinter

1
我已经实现了@willgiynn的一部分解决方案,修改了application_controller.rb中的current_ability方法。
ability.rb中:
class UserAbility
  include CanCan::Ability

  def initialize(user)
    can :read, :all
  end
end

class AdminAbility
  include CanCan::Ability

  def initialize(admin)
    can :manage, :all
  end
end

application_controller.rb 文件中。
def current_ability
  @current_ability ||= current_admin ? AdminAbility.new(current_admin) : UserAbility.new(current_user)
end

希望它有所帮助!

0

我会补充willgiynn的回答。看起来我需要添加更多的代码才能使它工作。我从这个帖子中找到了答案。

将以下内容添加到application_controller.rb

  def current_ability
    if admin_signed_in?
      @current_ability ||= Ability.new(current_admin)
    else
      @current_ability ||= Ability.new(current_user)
  end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接