From d217e48356a715949ce83dd21771bb30d8ba85ec Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Sat, 21 Feb 2026 14:43:29 +0100 Subject: [PATCH] fix: eager load permissions and organisers in DashboardController Motivation: Bullet was reporting N+1 queries on the homepage (/). The view accesses event.organisers which requires the permissions join table to be eager loaded. Analysis: - The all_events method loads Event and Workshop objects that need organisers and permissions preloaded - Also fixed Meeting eager loading to include permissions - Changed from includes() to eager_load() to handle nested through-associations (organisers goes through permissions) Before: N+1 queries per event for organisers After: Single query with JOIN on permissions table. --- app/controllers/dashboard_controller.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 43833093e..8d710c5ef 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -55,20 +55,19 @@ def top_coach_query end def upcoming_events - workshops = Workshop.upcoming.includes(:chapter, :sponsors, :organisers) + workshops = Workshop.eager_load(:chapter, :sponsors, :organisers, :permissions).upcoming.to_a all_events(workshops).sort_by(&:date_and_time).group_by(&:date) end def upcoming_events_for_user - chapter_workshops = Workshop.upcoming + chapter_workshops = Workshop.eager_load(:chapter, :sponsors, :organisers, :permissions) .where(chapter: current_user.chapters) - .includes(:chapter, :sponsors, :organisers) .to_a accepted_workshops = current_user.workshop_invitations.accepted .joins(:workshop) .merge(Workshop.upcoming) - .includes(workshop: %i[chapter sponsors organisers]) + .eager_load(workshop: %i[chapter sponsors organisers permissions]) .map(&:workshop) all_events(chapter_workshops + accepted_workshops) @@ -77,8 +76,9 @@ def upcoming_events_for_user end def all_events(workshops) - meeting = Meeting.includes(:venue, :organisers).next - events = Event.includes(:venue, :sponsors, :organisers).upcoming.take(DEFAULT_UPCOMING_EVENTS) + meeting = Meeting.eager_load(:venue, :organisers, :permissions).next + events = Event.eager_load(:venue, :sponsors, :sponsorships, :permissions, + :organisers).upcoming.take(DEFAULT_UPCOMING_EVENTS) [*workshops, *events, meeting].uniq.compact end