Vik*_*nic 6 activeadmin rolify pundit
我将 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
Run Code Online (Sandbox Code Playgroud)
这样就导致每次N+1次查询scope.where(id: record.id).exists?。在索引页上,show?为表中的每条记录调用 、update?和。destroy?
这种情况下如何避免N+1查询呢?
我正在尝试:1)与用户一起包含/预加载角色以进行调用current_user
2)我正在尝试记住或使用某种数组方法来防止使用和方法scope击中数据库。但仍然对每个新行进行数据库查询。whereexists?scope.find
谢谢!
首先,我建议向User对象添加一个方法来返回 company_ids ,这对员工有帮助。
class User #or AdminUser right?
def company_ids
@company_ids ||= Company.with_role(:staff, self).map(&:id)
end
end
Run Code Online (Sandbox Code Playgroud)
你无法改变
def destroy?
scope.where(id: record.id).exists?
end
Run Code Online (Sandbox Code Playgroud)
到
def destroy?
return true user.admin?
user.company_ids.include?(record.company_id)
end
Run Code Online (Sandbox Code Playgroud)
范围的解析方法现在看起来像这样
def resolve
if user.admin?
scope.all
else
scope.where(company_id: user.company_ids)
end
end
end
Run Code Online (Sandbox Code Playgroud)