Use role caching for Rolify to avoid N+1 queries

Resolves #2018

See https://github.com/RolifyCommunity/rolify#cached-roles-to-avoid-n1-issue
This commit is contained in:
James Mason 2018-03-28 17:31:18 -07:00
parent 30ba7b133b
commit 98defe2d0f
13 changed files with 44 additions and 35 deletions

View file

@ -13,10 +13,10 @@ module Admin
redirect_to sign_in_path
return false
end
unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) ||
(current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) ||
(current_user.has_role? :volunteers_coordinator, :any) ||
(current_user.has_role? :track_organizer, :any) || current_user.is_admin
unless (current_user.has_cached_role? :organizer, :any) || (current_user.has_cached_role? :cfp, :any) ||
(current_user.has_cached_role? :info_desk, :any) || (current_user.has_cached_role? :organization_admin, :any) ||
(current_user.has_cached_role? :volunteers_coordinator, :any) ||
(current_user.has_cached_role? :track_organizer, :any) || current_user.is_admin
raise CanCan::AccessDenied.new('You are not authorized to access this page.')
end
end

View file

@ -45,7 +45,7 @@ module Admin
end
def assign_org_admins
if @user.has_role? 'organization_admin', @organization
if @user.has_cached_role? 'organization_admin', @organization
flash[:error] = "User #{@user.email} already has the role organization admin"
elsif @user.add_role 'organization_admin', @organization
flash[:notice] = "Successfully added role organization admin to user #{@user.email}"

View file

@ -86,7 +86,7 @@ module Admin
else
flash[:error] = "Could not remove role #{@role.name} from user #{user.email}"
end
elsif user.has_role? @role.name, role_resource
elsif user.has_cached_role? @role.name, role_resource
flash[:error] = "User #{user.email} already has the role #{@role.name}"
# Add user
elsif user.add_role @role.name, role_resource

View file

@ -6,7 +6,7 @@ module Admin
def index
@conferences_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title)
if current_user.has_role? :organization_admin, :any
if current_user.has_cached_role? :organization_admin, :any
@conferences_with_role = Organization.with_role('organization_admin', current_user).map { |org| org.conferences.pluck :short_title }.flatten
end
@conferences_with_role.uniq!

View file

@ -1,7 +1,7 @@
module Admin
module VolunteersHelper
def can_manage_volunteers?(conference)
current_user.has_role?(:organizer, conference) || current_user.has_role?(:volunteers_coordinator, conference)
current_user.has_cached_role?(:organizer, conference) || current_user.has_cached_role?(:volunteers_coordinator, conference)
end
end
end

View file

@ -5,8 +5,8 @@ class AdminAbility
# Order Abilities
# (Check https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence)
# Check roles of user, using rolify. Role name is *case sensitive*
# user.is_organizer? or user.has_role? :organizer
# user.is_cfp_of? Conference or user.has_role? :cfp, Conference
# user.is_organizer? or user.has_cached_role? :organizer
# user.is_cfp_of? Conference or user.has_cached_role? :cfp, Conference
# user.is_info_desk_of? Conference
# user.is_volunteers_coordinator_of? Conference
# user.is_attendee_of? Conference
@ -79,12 +79,12 @@ class AdminAbility
# Abilities for signed in users with roles
def signed_in_with_roles(user)
signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any
signed_in_with_organizer_role(user) if user.has_role? :organizer, :any
signed_in_with_cfp_role(user) if user.has_role? :cfp, :any
signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any
signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any
signed_in_with_track_organizer_role(user) if user.has_role? :track_organizer, :any
signed_in_with_organization_admin_role(user) if user.has_cached_role? :organization_admin, :any
signed_in_with_organizer_role(user) if user.has_cached_role? :organizer, :any
signed_in_with_cfp_role(user) if user.has_cached_role? :cfp, :any
signed_in_with_info_desk_role(user) if user.has_cached_role? :info_desk, :any
signed_in_with_volunteers_coordinator_role(user) if user.has_cached_role? :volunteers_coordinator, :any
signed_in_with_track_organizer_role(user) if user.has_cached_role? :track_organizer, :any
common_abilities_for_roles(user)
end

View file

@ -6,6 +6,9 @@ end
class User < ApplicationRecord
rolify
# prevent N+1 queries with has_cached_role? by preloading roles *always*
default_scope { preload(:roles) }
has_many :physical_tickets, through: :ticket_purchases do
def by_conference(conference)
where('ticket_purchases.conference_id = ?', conference)

View file

@ -73,7 +73,7 @@
method: :patch, class: 'btn btn-mini btn-success', id: "resubmit_track_request_#{track.id}"
- if can? :edit, track
= link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default'
- if current_user.has_role? :track_organizer, track
- if current_user.has_cached_role? :track_organizer, track
= link_to 'Manage', admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default'
.row

View file

@ -8,7 +8,7 @@
.btn-group.pull-right
- if can? :edit, @track
= link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary'
- if current_user.has_role? :track_organizer, @track
- if current_user.has_cached_role? :track_organizer, @track
= link_to 'Manage', admin_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-default'
.row
.col-md-8