使用Pundit进行全访问“super_admin”角色

时间:2015-05-07 05:46:11

标签: ruby-on-rails authorization pundit

我想知道使用Pundit gem给用户“super_admin”访问的最佳/最简单方法 - 或者,让用户访问整个站点的所有控制器操作的最简单方法是什么?

我意识到我可以编辑每个控制器的策略文件,然后添加类似

的内容
def delete?
  user.is_super_admin?
end

...对每一个控制器中的每一个动作。但是我可以在一个地方定义这个吗?

我已经看过了我的所有其他控制器策略继承的应用程序策略,但我相信这些操作都会在我的控制器中被覆盖,所以我认为我不能在那里定义它。

我确定其他人需要实现此功能吗?什么是最简单的方法?谢谢!

1 个答案:

答案 0 :(得分:2)

对于(实际上)在项目生命周期中重复输入方法名称的最小烦恼,我认为可能不那么明显的好处是值得的。

首先,您可以通过在super?

上定义ApplicationPolicy方法来保存一些按键操作
def super?
  user.is_super_admin?
end

然后您的delete?和其他方法可以简化一点。

def delete?
  super? || user.id == record.user_id # super admin or owner of the resource
end

Pundit政策很简单。如果我之前从未使用过您的代码,我可以查看上面的方法,并确切知道谁可以执行删除。

当然,它可能会为您节省几笔按键,以便有一些元编程功能可以自动调用super?delete?显示为

def delete?
  user.id == record.user_id # super admin or owner of the resource
end

但现在失去了清晰度。此外,如果有一种方法,你希望超级管理员有权访问?重新设计已经更复杂的解决方案会使事情更容易出错并且更难以理解。所有这些都可以保存每种方法~10次击键。

更新

除了关于代码可读性的意见之外,这里有一个实现,它可以完成您的工作。您也可以查看hooking the method calls而不是从方法名称中移除?,如下所示,以确保method_missing选择它们。

#
# Classes
#

User = Struct.new(:id, :name)
Foo  = Struct.new(:id, :title, :user_id)

class SuperUser < User; end

ApplicationPolicy = Struct.new(:user, :record) do

  attr_reader :user, :record

  def initialize(user, record)
    @user   = user
    @record = record
  end

  def method_missing(name)
    raise NoMethodError, "No method `#{name}` for #{self}" if (name =~ /\?$/).nil?

    user.is_a?(SuperUser) || send(name.to_s.sub(/\?$/, ""))
  end

end

class FooPolicy < ApplicationPolicy

  private

    def edit
      user.id == record.user_id
    end

end


#
# Fixtures
#

user = User.new(1, "Deefour")
foo  = Foo.new(1, "A Sample Foo", 1)

super_user = SuperUser.new(2, "FireDragon")


#
# Examples
#

FooPolicy.new(user, foo).edit?       #=> true
FooPolicy.new(super_user, foo).edit? #=> true