Rails - 政策中有 Pundit Scopes

Rails - with Pundit Scopes in policy

我正在尝试弄清楚如何在我的文章政策中使用专家政策范围。

我写了一篇文章政策,它嵌套了一个范围,然后在其中有一个解析方法。 resolve 方法有基于 current_user 是谁的替代方法。

我的文章政策有:

class ArticlePolicy < ApplicationPolicy
    class Scope < Scope
        attr_reader :user, :scope

        # I now think I don't need these actions because I have changed the action in the articles controller to look for policy scope.
         # def index?
         #      article.state_machine.in_state?(:publish)
         # end

            def show?

            article.state_machine.in_state?(:publish) ||
            user == article.user ||
            article.state_machine.in_state?(:review) && user.org_approver ||
            false
        end
            end

            def create?
                article.user.has_role?(:author) 

            end

            def update?
                # user && user.article.exists?(article.id) #&& user.article.created_at < 15.minutes.ago
                user.present? && user == article.user 
                # add current state is not published or approved
            end

            def destroy?
                user.present? && user == article.user 
                # user.admin? 
                # user.present?
                # user && user.article.exists?(article.id)
            end



    end     

    private
        def article
            record
        end

        def resolve
            if user == article.user
                scope.where(user_id: user_id)
            elsif approval_required?
                scope.where(article.state_machine.in_state?(:review)).(user.has_role?(:org_approver))
            else
                article.state_machine.in_state?(:publish)    
            end 
        end


        def approval_required?

            true if article.user.has_role?(:author)
                 # elsif article.user.profile.organisation.onboarding.article_approval == true


            # if onboarding (currently in another branch) requires org approval
        end

        def org_approver
            if article.user.has_role? :author
                user.has_role? :editor
            # if onboarding (currently in another branch) requires org approval, then the approval manager for that org
            elsif article.user.has_role? :blogger
                user.has_role? :editor if user.profile.organisation.id == article.user.profile.organisation.id  
          end
        end

end

pundit 文档中的示例显示了如何将其用于索引,但我如何将 resolve 方法用于显示操作?我可以为各种其他控制器操作编写多个解析方法吗?

Pundit Scopes

我对 pundit 没有太多经验,但是通过查看文档和您的代码,我可以看到两件事。

1 - 你不应该在你的范围 class.

中使用像 show? 这样的方法

在您的范围 class 内,您应该只使用 returns 范围内的方法。 returns boolean 的方法应该在 Policy 级别。但是在您的代码中,我可以在 class 范围内使用布尔方法。

Instances of this class respond to the method resolve, which should return some kind of result which can be iterated over. For ActiveRecord classes, this would usually be an ActiveRecord::Relation.

from the docs

2 - 鉴于 Scope 是 PORO(普通旧 Ruby 对象),您可以有多个解析方法(当然名称不同 :)),因为解析只是一个方法名称。

也许你可以做类似的事情

#policy
class ArticlePolicy < ApplicationPolicy
  attr_reader :user, :scope

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


  class Scope < Scope
    def resolve
      # some scope
    end

    def resolve_show
      #scope for show action 
      # E.g scope.all
    end
  end

  def show?
    article.state_machine.in_state?(:publish) ||
      user == article.user ||
      article.state_machine.in_state?(:review) && user.org_approver || false
  end
end

在你的控制器中

#Articles controller
class ArticlesController < ApplicationController
  ...
  def show
    authorize Article 
    ArticlePolicy::Scope.new(current_user, Article).resolve_show
  end
  ...
end

这应该首先使用 ArticlePolicy#show?ArticlePolicy::Scope#resolve_show

的范围授权您的显示方法

免责声明:未经测试的代码,使用风险自负;)