Skip to content

Admin chapter workshops index is unbounded (no pagination + per-row COUNT queries) #2899

Description

@mroderick

Summary

Admin::WorkshopsController#index (/admin/chapters/:chapter_id/workshops) loads every workshop for the chapter and runs one extra SQL COUNT per rendered row. Slow on older chapters — chapter 1 (London) has ~13 years of workshops (~700+).

Symptom

  • One page view loads 700+ Workshop records and renders 700+ <tr> rows.
  • Each row's workshop.invitations.accepted.count emits a separate SQL COUNT — ~700 queries per page view.
  • Memory, DB time, and DOM size all scale with chapter age, so the page degrades as the chapter grows.

Root cause (two compounding problems)

1. Unbounded result set

app/controllers/admin/workshops_controller.rb:

@workshops = @chapter.workshops.includes(:sponsors)

No pagination. The view renders all rows in a single table.

2. N+1 COUNT queries in the view

app/views/admin/workshops/index.html.haml:

= workshop.invitations.accepted.count

One query per workshop per render. Each COUNT is cheap (index index_workshop_invitations_workshop_attending exists), but the round trips accumulate across all rows.

Proposed fix

Paginate with Pagy (already used elsewhere in this controller, e.g. #rsvp):

@pagy, @workshops = pagy(@chapter.workshops.includes(:sponsors), items: 50)

Ordering is already deterministic via default_scope { order('date_and_time DESC') } and index_workshops_on_date_and_time, so offset pagination is fine at codebar's scale.

Replace per-row COUNTs with one aggregate query, keyed by workshop id and looked up in the view:

@accepted_counts = @workshops.joins(:invitations)
                             .where(invitations: { attending: true })
                             .group('invitations.workshop_id').count

Optional follow-ups (only if still slow after the above)

  • Default the listing to upcoming + recent past (e.g. where(date_and_time: 1.year.ago..)) with a link to the full list.
  • Fragment caching per row — probably unnecessary once pagination lands.

Acceptance criteria

  • The page is paginated and renders a bounded number of rows regardless of chapter age.
  • Query count drops from O(workshops) to O(1): pagination count query + one aggregate + sponsors preload.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions