我目前让Devise和Pundit在一个封闭的系统中运行良好,该系统要求用户登录才能看到任何东西。
新目标:如何使用Pundit要求AdminUser登录才能访问Admin名称空间?
我有一个单独的AdminUser模型,一个单独的Admin控制器,策略和命名空间:
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 (管理员命名空间的子策略示例)
class Admin::HomePolicy < Admin::AdminPolicy
def index?
user.present?
end
end
这两个策略的设置方式都与我的用户策略相同,因此,它们都不在寻找AdminUser。如何在AdminUser模型中使用这些功能?
答案 0 :(得分:1)
我认为您在正确的轨道上。您已经为您的管理控制器创建了一个命名空间,该命名空间继承自Admin::AdminController
。 Pundit向您的ApplicationController
注入一个名为pundit_user
的辅助方法,默认情况下,该方法仅返回current_user
。
尽管您可以考虑不为管理员使用单独的模型,而是使用适当的授权设置,但这可能并不适合所有情况。我只想把它放在那里供您考虑。
解决这个问题的最简单方法就是简单地覆盖Admin::AdminController
中的helper方法,如下所示:
class Admin::AdminController < ApplicationController
def pundit_user
current_admin_user
end
end
请注意,这确实是假设AdminUser模型是在this convention行的某处设置的