代码之家  ›  专栏  ›  技术社区  ›  Rowandish

具有两个输入参数的专家策略

  •  14
  • Rowandish  · 技术社区  · 10 年前

    我对Rails很熟悉,我对以下策略(使用 Pundit ):我想比较两个对象: @record @foo ,如您所见:

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

    我没有找到一个好的方法将第二个参数传递给pundit方法(@foo)。

    我想做一些事情,比如:

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

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

    谢谢

    4 回复  |  直到 10 年前
        1
  •  19
  •   Rowandish    10 年前

    我在找到答案 here .

    这是我的方法:

    添加 pundit_user 中的函数 ApplicationController :

    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
    

    更新initialize Pundit方法。

    class ApplicationPolicy
      attr_reader :user, :record, :foo
    
      def initialize(context, record)
        @user = context.user
        @foo = context.foo
        @record = record
      end
    end
    
        2
  •  1
  •   István Ujj-Mészáros    5 年前

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

    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
    

    这个 skip_authorization && 如果 after_action :verify_authorized 没有使用,我只是想展示一个在这种情况下可以使用的单行,以消除未授权的异常,同时仍然需要授权操作。

        3
  •  1
  •   Peter Gerdes    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
    

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

        4
  •  0
  •   rnewed_user    2 年前

    除了来自@Rowandish,在我的情况下,我不得不使用 query_parameters (以访问属性id):

    class CurrentContext
      attr_reader :user, :record, :article_id
    
      def initialize(user, record)
        @user = user
        @article_id = record.query_parameters['id']
      end
    
    end
    

    并这样定义了专家用户:

    def pundit_user
        CurrentContext.new(current_user, request)
    end
    

    在我的控制器中,我正在执行这个请求

     def index
        @article = Article.find(params[:id])
        render json: policy_scope(article)
     end
    

    最后我的警察是这样的:

    class ArticlePolicy < ApplicationPolicy
      attr_reader :user, :article
    
      def initialize(context, record)
        @user = context.user
        @article_id = context.article_id
        @articles = record
      end
    
      class Scope < ArticlePolicy
        
        def resolve
            Article.find(@article_id) if ArticleUser.where(article_id: @article_id, user_id: @user.id).present?
        end
    
      end
    end