Rails - 将 Pundit 与单独的管理命名空间一起使用

Rails - using Pundit with a separate admin namespace

我目前让 Devise 和 Pundit 在一个封闭的系统中工作得很好,需要用户登录才能看到任何东西。

新目标:如何使用 Pundit 要求 AdminUser 登录以访问 Admin 命名空间?

我有一个单独的 AdminUser 模型、单独的管理控制器、策略和命名空间:

routes.rb

namespace :admin do
  root to: 'home#index'
  resources :users
end

devise_for :admin_users, skip: [:sessions]
as :admin_user do
  get 'admin/signin', to: 'admin/devise/sessions#new', as: :new_admin_user_session
  post 'admin/signin', to: 'admin/devise/sessions#create', as: :admin_user_session
  delete 'admin/signout', to: 'admin/devise/sessions#destroy', as: :destroy_admin_user_session
end

controllers/admin/admin_controller.rb

class Admin::AdminController < ApplicationController

end

controllers/admin/home_controller.rb

class Admin::HomeController < Admin::AdminController

  def index
    authorize [:admin, :home]
  end

end

policies/admin/admin_policy.rb(封闭系统,目前寻找User而不是AdminUser)

class Admin::AdminPolicy
  attr_reader :user, :record

  def initialize(user, record)
    # Must be logged in
    raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    false
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
      @user = user
      @scope = scope
    end

    def resolve
      scope.all
    end
  end
end

policies/admin/home_policy.rb(Admin 命名空间的示例子策略)

class Admin::HomePolicy < Admin::AdminPolicy

  def index?
    user.present?
  end

end

这两个策略的设置方式与我的用户策略相同,因此不是在寻找 AdminUser。我怎样才能使这些适用于我的 AdminUser 模型?

我认为您的方向是正确的。您已经为您的管理控制器创建了一个命名空间,它继承自 Admin::AdminController。 Pundit 在你的 ApplicationController 中注入了一个名为 pundit_user 的辅助方法,默认情况下只是 returns current_user.

虽然您可以考虑不为管理员使用单独的模型,而是使用适当的授权设置,但这可能并不适合所有情况。我只是想把它放在那里供你考虑。

我能想到的解决此问题的最简单方法是简单地覆盖 Admin::AdminController 中的辅助方法,如下所示:

class Admin::AdminController < ApplicationController
  def pundit_user
    current_admin_user
  end
end

请注意,这确实假设 AdminUser 模型是在 this convention

的某处设置的