Skip to content

Bound Activity loads on ActivityParticipation admin forms - #178

Merged
thibaudgg merged 2 commits into
masterfrom
cursor/bound-activity-participation-form-51d0
Sep 14, 2026
Merged

thibaudgg merged 2 commits into
masterfrom
cursor/bound-activity-participation-form-51d0

Conversation

@thibaudgg

@thibaudgg thibaudgg commented Sep 14, 2026

Copy link
Copy Markdown
Member

Problem

ActivityParticipationsController#edit (and #new, same ActiveAdmin form) got slower in production because the activity dropdown loaded every past Activity with SELECT * and no LIMIT.

AppSignal CSA Admin / production, Europe/Zurich week 7–14 Sep 2026:

  • Action: ActivityParticipationsController#edit
  • Regression vs prior week: p95 ~222ms → ~408ms (n≈27 this week)
  • Slow traces 0.65–1.9s across tenants; all flagged N+1
  • Worst cluster: tenant clefdeschamps, rev 6de5f427…, ~1.8–1.9s on 12 Sep ~15:21 CEST

Trace 13f9da2263b7dce15f02c3d0c0f26b97 (1899.9ms):

  • Layout/form dominate: active_admin/resource/edit_form ≈1719ms
  • Hotspot SQL (no LIMIT):
SELECT "activities".* FROM "activities" WHERE "activities"."date" < ? ORDER BY "activities"."date" DESC
  • That Activity Load was ~69ms SQL + ~370ms ActiveRecord instantiation with ~94k allocations

Coming activities used the same unbounded SELECT * (cheap on that tenant). A follow-up WHERE id = ? LIMIT ? Activity Load and the member select remain; those are single-row / needed dropdown data, not the hotspot.

Change

The form called grouped_by_date(Activity), which instantiates the full past (and coming) relation for the select.

It now uses Activity.admin_form_collection:

  • Coming and past groups are each LIMIT 200
  • Only label columns are selected (id, date, start_time, end_time, places)
  • An already-assigned activity outside that window stays in the select so edit stays usable
  • UI is unchanged: Coming / Past optgroups, same labels

No new frontend stack. Member collection is unchanged (needed for the member select; ~4.5ms in the trace).

Tests

Controller and model tests assert the form Activity queries stay bounded as activity count grows (LIMIT, no SELECT *, no descriptions / titles / place_urls), and that an assigned activity older than the limit remains selected.

Locally: bin/rails test test/models/activity_test.rb test/controllers/activity_participations_controller_test.rb and RuboCop on the touched files are green.

Open in Web Open in Cursor 

cursoragent and others added 2 commits September 14, 2026 07:54
Stop loading every past Activity into the ActiveAdmin new/edit
select. The form now queries a column-narrowed, LIMIT 200 coming
and past collection and always keeps the assigned activity.

Co-authored-by: Thibaud Guillaume-Gentil <thibaud@thibaud.gg>
Activity collection loads bind LIMIT as ?, so assert the clause
instead of a literal 200.

Co-authored-by: Thibaud Guillaume-Gentil <thibaud@thibaud.gg>
@thibaudgg
thibaudgg marked this pull request as ready for review September 14, 2026 16:08
@thibaudgg
thibaudgg merged commit 221fe7f into master Sep 14, 2026
4 checks passed
@thibaudgg
thibaudgg deleted the cursor/bound-activity-participation-form-51d0 branch September 15, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants