【问题标题】:Pundit policies with two input parameters具有两个输入参数的 Pundit 策略
【发布时间】:2015-01-29 14:05:42
【问题描述】:

我是 Rails 的新手,我对以下策略有疑问(使用 Pundit):我想比较两个对象:@record@foo,您可以在此处看到:

class BarPolicy < ApplicationPolicy
  def show?
    @record.foo_id == @foo
  end
end

我找不到将第二个参数传递给权威方法 (@foo) 的好方法。

我想做这样的事情:

class BarsController < ApplicationController
  def test
    authorize bar, @foo, :show? # Throws ArgumentError
    ...
  end
end

但是 Pundit 授权方法只允许两个参数。 有没有办法解决这个问题?

谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 pundit policies


    【解决方案1】:

    我在here找到了答案。

    这是我的方式:

    ApplicationController中添加pundit_user函数:

    class ApplicationController < ActionController::Base
    include Pundit
    def pundit_user
        CurrentContext.new(current_user, foo)
    end
    

    创建CurrentContext 类:

    /lib/pundit/current_context.rb
    class CurrentContext
      attr_reader :user, :foo
    
      def initialize(user, foo)
        @user = user
        @foo = foo
      end
    end
    

    更新初始化 Pundit 方法。

    class ApplicationPolicy
      attr_reader :user, :record, :foo
    
      def initialize(context, record)
        @user = context.user
        @foo = context.foo
        @record = record
      end
    end
    

    【讨论】:

    • 是的 this is 正确的记录方式。
    • 写这么多代码只是为了在没有其他方法需要的情况下将参数传递给单个策略方法有什么意义。
    • 我同意,不幸的是,一些纯粹主义者认为这是一种“代码味道”,但它只会让像我这样的凡人感到困惑。
    【解决方案2】:

    依赖于当前用户和域模型是一种代码味道,但如果确实需要,那么您可以使用带有任意数量参数的自定义查询方法,如果需求不满足则引发异常遇见:

    class BarPolicy < ApplicationPolicy
      def authorize_test?(foo)
        raise Pundit::NotAuthorizedError, "not authorized to test" unless record.foo_id == foo
      end
    end
    
    class BarsController < ApplicationController
      def test
        skip_authorization && BarPolicy.new(current_user, @record).authorize_test?(@foo)
        ...
      end
    end
    

    如果不使用after_action :verify_authorized,则不需要skip_authorization &amp;&amp; 部分,我只是想展示一个可以在这种情况下使用的单行代码,以消除未经授权的异常,同时仍然需要授权该操作。

    【讨论】:

      【解决方案3】:

      我不明白这个想法是什么,将额外的参数传递给 Pundit 是不好的编码。我的意思是,当然,这就像一个大案例陈述。如果您可以通过更好的设计来避免这种情况,那么就这样做,但您通常会面临将授权逻辑散布到其他文件中或将额外信息传递给 Pundit 的选择。

      这是我编写的代码,让我可以使用我的 Pundit 类来检查是否允许用户对给定的列进行排序(resource_class 是我编写的另一种方法,它返回关联控制器中关联的 activerecord 类):

          def authorize_sort(column, record = resource_class)
              Pundit.policy!(user, record)
              unless policy.allow_sort?(column)
                  raise NotAuthorizedError, "Not authorized to sort on column #{column} on record #{record}"
              end
          end
      

      如果您不希望您的授权逻辑分布在更多类上并希望允许用户对其他用户看不到的字段进行排序,这确实是不可避免的。如果没有创建特殊的活动记录排序对象,这是不可避免的,因为它不是您要返回的任何单个对象的属性,而是它们排序所在的列。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多