Rails - 政策中的Pundit Scopes

时间:2016-07-05 08:31:20

标签: ruby-on-rails pundit scopes

我试图弄清楚如何在我的文章政策中使用权威政策范围。

我写了一篇文章策略,它嵌套了一个范围,然后在其中有一个解决方法。解决方法具有基于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

专家文档中的示例显示了如何将其用于索引,但如何将resolve方法用于show动作?我可以为各种其他控制器操作编写几种解决方法吗?

Pundit Scopes

1 个答案:

答案 0 :(得分:1)

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

1 - 您不应在范围类中使用show?之类的方法。

在范围类中,您应该只使用返回范围的方法。返回布尔值的方法应该在策略级别。但是在你的代码中,我可以在范围类中使用布尔方法。

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(Plain Old Ruby Object),你可以拥有多个解析方法(当然使用不同的名称:)),因为resolve只是一个方法名称。

可能你可以做点什么

#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

范围授权您的show方法

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