【问题标题】:How to avoid N+1 in Pundit policy for show?/update?/destroy?如何避免 Pundit 政策中的 N+1 用于 show?/update?/destroy?
【发布时间】:2020-06-10 12:20:32
【问题描述】:

我将 ActiveAdmin gem 与 Pundit(和 Rolify)gem 一起使用。

这就是我编写策略的方式(取自:https://github.com/activeadmin/activeadmin/blob/master/spec/support/templates/policies/application_policy.rb):

class ApplicationPolicy
  attr_reader :user, :record

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

  def show?
    scope.where(id: record.id).exists?
  end

  def create?
    user.has_role?(:staff, record.company)
  end

  def update?
    scope.where(id: record.id).exists?
  end

  def destroy?
    scope.where(id: record.id).exists?
  end

  def destroy_all?
    true
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :user, :scope

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

    def resolve
      if user.admin?
        scope.all
      else
        company_ids = Company.with_role(:staff, user).map(&:id)
        scope.where(company_id: company_ids)
      end
    end
  end
end

这会导致每次scope.where(id: record.id).exists? 进行 N+1 次查询。在索引页上,为表中的每条记录调用show?update?destroy?

在这种情况下如何避免 N+1 查询?

我正在尝试: 1) 包括/预加载角色与用户一起调用current_user 2)我正在尝试记忆scope 或使用一些数组方法来防止使用whereexists? 方法访问数据库。但是scope.find 仍然对每个新行进行 db 查询。

谢谢!

【问题讨论】:

    标签: activeadmin pundit rolify


    【解决方案1】:

    首先,我建议在User 对象中添加一个方法,以便在员工帮助的地方返回company_ids。

    class User #or AdminUser right?
      def company_ids
          @company_ids ||= Company.with_role(:staff, self).map(&:id)
      end
    end
    
    

    你可以改变

     def destroy?
        scope.where(id: record.id).exists?
      end
    

     def destroy?
        return true user.admin?
        user.company_ids.include?(record.company_id)
      end
    

    Scope 的解析方法现在看起来是这样的

    def resolve
          if user.admin?
            scope.all
          else
            scope.where(company_id: user.company_ids)
          end
        end
      end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多