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

Open
#2,899 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
rails, ruby

Research direction

Start with app/controllers/admin/workshops_controller.rb and the #rsvp pagination example, then inspect app/views/admin/workshops/index.html.haml where accepted invitation counts are rendered. Add bounded pagination and replace per-row counts with the aggregate lookup described in the issue; done means the page renders a fixed number of rows and meets the stated query-count criteria.

Written by the indexing model from the issue text.

Description

good first issue performance

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.
Dominant language
Ruby
Stars
104
Forks
205
Avg merge
1d 6h
Merged PRs (30d)
65

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from codebar/planner

All issues in codebar/planner

Similar issues

More Ruby issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.