From 1b691ae16bcf595a83db617f9c16d3e7b2552171 Mon Sep 17 00:00:00 2001 From: Nat Budin Date: Thu, 6 Aug 2026 09:16:46 -0700 Subject: [PATCH] Fix N+1 query on signup bucket/requested_bucket in UserConProfileDrop#signups Sentry showed a new registration_policy_buckets-by-id N+1 (INTERCODE-186/187/189) after #11880 shipped -- it had been masked by the much larger registration_policy/buckets N+1 that #11880 fixed, and became the dominant N+1 once that one was gone. Traced it to the "My Schedule" widget (the user_signups/signup_bucket_description CMS partials, present by default on most conventions' sites), which calls signup.bucket.name / signup.requested_bucket.name per signup. UserConProfileDrop#signups already preloads several associations but never picked up :bucket/:requested_bucket -- these only became real belongs_to associations in #11871 (they used to be plain string columns needing no extra query at all), so this gap predates #11880 but was previously hidden under the louder N+1. Co-Authored-By: Claude Sonnet 5 --- app/liquid_drops/user_con_profile_drop.rb | 13 +++++++++- .../user_con_profile_drop_test.rb | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/liquid_drops/user_con_profile_drop.rb b/app/liquid_drops/user_con_profile_drop.rb index 7eb84f6855c..f3bd0b5bc2e 100644 --- a/app/liquid_drops/user_con_profile_drop.rb +++ b/app/liquid_drops/user_con_profile_drop.rb @@ -51,6 +51,7 @@ class UserConProfileDrop < Liquid::Drop # @api def initialize(user_con_profile) + super() @user_con_profile = user_con_profile end @@ -65,7 +66,17 @@ def signups user_con_profile .signups .where.not(state: "withdrawn") - .includes(event: :event_category, run: { rooms: nil, event: { team_members: :user_con_profile } }) + .includes( + :bucket, + :requested_bucket, + event: :event_category, + run: { + rooms: nil, + event: { + team_members: :user_con_profile + } + } + ) .to_a end diff --git a/test/liquid_drops/user_con_profile_drop_test.rb b/test/liquid_drops/user_con_profile_drop_test.rb index f9817eaa8fd..914ef9cf68d 100644 --- a/test/liquid_drops/user_con_profile_drop_test.rb +++ b/test/liquid_drops/user_con_profile_drop_test.rb @@ -63,5 +63,30 @@ signups = user_con_profile_drop.signups withdrawn_signups.each { |signup| assert_not_includes signups, signup } end + + it "does not issue a bucket query per signup" do + queries = + count_queries(/registration_policy_buckets/) do + user_con_profile_drop.signups.each do |signup| + signup.bucket + signup.requested_bucket + end + end + assert_operator queries, :<=, 2, "expected a constant number of bucket queries regardless of signup count" + end + end + + private + + def count_queries(pattern) + count = 0 + subscriber = + ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload| + count += 1 if pattern.match?(payload[:sql]) + end + yield + count + ensure + ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber end end