I'm using ActiveAdmin gem together with Pundit (and Rolify) gem.
This is how I wrote my policy (taken from: 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
This causes N+1 query each time scope.where(id: record.id).exists?
. On index page, show?
, update?
and destroy?
are called for each record in the table.
How can I avoid the N+1 query in this case?
I'm trying to:
1) Include/preload roles together with user for calls to current_user
2) I'm trying to memoize the scope
or use some array method to prevent hitting the db with where
and exists?
methods. But scope.find
still makes the db query for every new row.
Thanks!