Skip to content

Commit 1c88e96

Browse files
authored
Merge pull request #2507 from mroderick/fix/n1-queries-events
fix: eliminate N+1 queries in EventsController#index
2 parents 17c0219 + f923e94 commit 1c88e96

6 files changed

Lines changed: 27 additions & 22 deletions

File tree

app/controllers/events_controller.rb

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,25 @@ class EventsController < ApplicationController
88
def index
99
fresh_when(latest_model_updated, etag: latest_model_updated)
1010

11-
events = [Workshop.past.includes(:chapter,
12-
:sponsors).joins(:chapter).merge(Chapter.active).limit(RECENT_EVENTS_DISPLAY_LIMIT)]
13-
events << Meeting.past.includes(:venue).limit(RECENT_EVENTS_DISPLAY_LIMIT)
14-
events << Event.past.includes(:venue, :sponsors, :sponsorships).limit(RECENT_EVENTS_DISPLAY_LIMIT)
11+
events = [Workshop.past
12+
.includes(:chapter, :sponsors, :host, :permissions)
13+
.joins(:chapter)
14+
.merge(Chapter.active)
15+
.limit(RECENT_EVENTS_DISPLAY_LIMIT)]
16+
events << Meeting.past.includes(:venue, :permissions).limit(RECENT_EVENTS_DISPLAY_LIMIT)
17+
events << Event.past.includes(:venue, :sponsors, :sponsorships, :permissions).limit(RECENT_EVENTS_DISPLAY_LIMIT)
1518
events = events.compact.flatten.sort_by(&:date_and_time).reverse.first(RECENT_EVENTS_DISPLAY_LIMIT)
1619
events_hash_grouped_by_date = events.group_by(&:date)
1720
@past_events = events_hash_grouped_by_date.map.each_with_object({}) do |(key, value), hash|
1821
hash[key] = EventPresenter.decorate_collection(value)
1922
end
2023

21-
events = [Workshop.includes(:chapter, :sponsors).upcoming.joins(:chapter).merge(Chapter.active)]
22-
events << Meeting.upcoming.all
23-
events << Event.upcoming.includes(:venue, :sponsors, :sponsorships).all
24+
events = [Workshop.upcoming
25+
.includes(:chapter, :sponsors, :host, :permissions)
26+
.joins(:chapter)
27+
.merge(Chapter.active)]
28+
events << Meeting.upcoming.includes(:venue, :permissions).all
29+
events << Event.upcoming.includes(:venue, :sponsors, :sponsorships, :permissions).all
2430
events = events.compact.flatten.sort_by(&:date_and_time).group_by(&:date)
2531
@events = events.map.each_with_object({}) do |(key, value), hash|
2632
hash[key] = EventPresenter.decorate_collection(value)

app/models/workshop.rb

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ class Workshop < ApplicationRecord
1010
has_many :invitations, class_name: 'WorkshopInvitation'
1111
has_many :workshop_sponsors
1212
has_many :sponsors, through: :workshop_sponsors
13+
has_one :workshop_host, -> { where(workshop_sponsors: { host: true }) },
14+
class_name: 'WorkshopSponsor',
15+
inverse_of: :workshop
16+
has_one :host, through: :workshop_host, source: :sponsor
1317
has_many :organisers, -> { where('permissions.name' => 'organiser') }, through: :permissions, source: :members
1418
has_many :feedbacks
1519

@@ -31,18 +35,7 @@ class Workshop < ApplicationRecord
3135
before_validation :set_opens_at
3236

3337
def host
34-
sql = <<~SQL
35-
SELECT sponsors.*
36-
FROM sponsors
37-
LEFT JOIN workshop_sponsors ON workshop_sponsors.sponsor_id = sponsors.id
38-
WHERE workshop_sponsors.workshop_id = ?
39-
AND workshop_sponsors.host = TRUE
40-
AND sponsors.id = workshop_sponsors.sponsor_id
41-
ORDER BY sponsors.updated_at DESC, workshop_sponsors.id ASC
42-
LIMIT 1
43-
SQL
44-
45-
Sponsor.find_by_sql([sql, id]).first
38+
workshop_host&.sponsor
4639
end
4740

4841
def waiting_list

app/models/workshop_sponsor.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class WorkshopSponsor < ApplicationRecord
22
belongs_to :sponsor
3-
belongs_to :workshop
3+
belongs_to :workshop, inverse_of: :workshop_sponsors
44

55
validates :sponsor_id, uniqueness: { scope: :workshop_id, message: :already_sponsoring }
66
end

app/presenters/workshop_presenter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def attending_and_available_coach_spots
2828
end
2929

3030
def venue
31-
model.host
31+
@venue ||= model.host
3232
end
3333

3434
def organisers
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddIndexWorkshopSponsorsHost < ActiveRecord::Migration[8.1]
2+
def change
3+
add_index :workshop_sponsors, %i[workshop_id host], name: 'index_workshop_sponsors_on_workshop_id_and_host'
4+
end
5+
end

db/schema.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[8.1].define(version: 2026_02_24_120000) do
13+
ActiveRecord::Schema[8.1].define(version: 2026_02_24_130000) do
1414
# These are extensions that must be enabled in order to support this database
1515
enable_extension "pg_catalog.plpgsql"
1616

@@ -565,6 +565,7 @@
565565
t.datetime "updated_at", precision: nil
566566
t.integer "workshop_id"
567567
t.index ["sponsor_id"], name: "index_workshop_sponsors_on_sponsor_id"
568+
t.index ["workshop_id", "host"], name: "index_workshop_sponsors_on_workshop_id_and_host"
568569
t.index ["workshop_id"], name: "index_workshop_sponsors_on_workshop_id"
569570
end
570571

0 commit comments

Comments
 (0)