【问题标题】:Cancancan Cant get it work with User and AdminCancancan 无法与用户和管理员一起使用
【发布时间】:2026-02-08 11:55:02
【问题描述】:

所以我在我的应用程序中使用 Cancancan gem。我有 Users 通过 Devise/Omniauth gems 和 Admins 通过简单的自定义身份验证进行身份验证。 我要实现

ability.rb

def initialize(userOrAdmin)

if userOrAdmin.user?
    can :read, User 
    return unless user.present?
    can :manage, User, id: user.id
  elsif userOrAdmin.admin? 
    can [:update, :read] , Admin, id: admin.id
  end
 end
end

但这不起作用。 我试图覆盖这样的能力方法

application_controller

 def current_ability

   if current_admin?
     @current_ability ||= Ability.new(current_admin)
   elsif current_user?
     @current_ability ||= Ability.new(current_user)
   end
 end

但我收到 nomethod current_admin 错误,这可能是因为 Cancancan 假定来自设备的 current_admin 但我使用自己的 current_admin 方法却找不到它。 p>

我还尝试在 User.rb 和 Admin.rb 中使用枚举分配角色并正确更改ability.rb,但我得到了一个 未定义的方法管理员?对于用户错误

Cancancan 版本 2.0

【问题讨论】:

  • “但那不起作用” - 如何以及在哪里不起作用?您要授权什么操作?
  • 你定义了#current_admin?。注意?,如果你想检查当前管理员是否存在,你可以做current_admin.present?
  • @MihaiTârnovan 我希望用户只有在他们是 current_user 时才能进行编辑,而对于管理员来说也一样,但也只有在他们是 current_admin 时才能显示。
  • @DavidS。我已经定义了 current_admin 这样 current_admin ||= Admin.find(session[:admin_id]) if session[:admin_id]
  • @MarkosTzetzis 准确地说,我认为您需要调用current_admin.present? 而不是current_admin?

标签: ruby-on-rails ruby cancancan


【解决方案1】:

我找到了一个可行的解决方案 application_controller.rb

def current_ability
 if current_user
        return if current_admin.present?
     @current_ability ||= Ability.new(current_user)
   elsif current_admin
        return unless current_admin.present?
     @current_ability ||= Ability.new(current_admin)
   end
 end

结束

ability.rb

class Ability
  include CanCan::Ability
  def initialize(userOrAdmin)
    if userOrAdmin.is_a? User
      can :read, User
      can [:update, :read], User, id: userOrAdmin.id
    elsif userOrAdmin.is_a?  Admin
      can :read, Admin
      can [:update, :read], Admin, id: userOrAdmin.id
   end
 end
end

虽然这可以正常工作。每当我像用户和管理员一样登录时,管理员角色都会出现 CanCan 未授权错误。

【讨论】:

    【解决方案2】:

    经过一番搜索,我发现了一些有用的文章:

    我建议您尝试以下方法:

    # Ability.rb
    class Ability
      include CanCan::Ability
    
      def initialize(user)
      # Everyone:
        can :read, User
      # Users:
        return unless user.present?
        can :manage, User, user_id: user.id
      # Admins:
        return unless user.admin?
        can :manage, :all
      end
    end
    
    # Routes.rb
    devise_for :users  # current_user:
    devise_for :admins  # current_admin: 
    
    # Application_Controller.rb
    def current_ability
      @current_ability ||= current_admin ? AdminAbility.new(current_admin) : UserAbility.new(current_user)
    end
    

    【讨论】:

    • 我明白了,您的建议中唯一的问题是我不想使用 devise_for : admin 。这就是导致这里所有问题的原因。