diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index 08c7e8163..e44839606 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -196,9 +196,13 @@ def load_events(rows)
(hash[row['event_type']] ||= []) << row['id'].to_i
end
+ # workshop_host must be preloaded: eager_loading it alongside :sponsors
+ # routes both through the workshop_sponsors table in one join, and the
+ # host scope then binds to the wrong table alias — the host comes back
+ # nil or points at a non-host sponsor. Same pattern as Listable.most_recent.
workshops = Workshop.eager_load(:sponsors, :organisers,
- workshop_host: :sponsor,
chapter: { permissions: :members })
+ .preload(workshop_host: :sponsor)
.where(id: grouped['Workshop'])
.to_a.index_by(&:id)
meetings = Meeting.eager_load(:venue, :organisers).where(id: grouped['Meeting'])
diff --git a/app/presenters/event_presenter.rb b/app/presenters/event_presenter.rb
index b00f500b1..d2614ea52 100644
--- a/app/presenters/event_presenter.rb
+++ b/app/presenters/event_presenter.rb
@@ -30,7 +30,7 @@ def short_description
end
def organisers
- @organisers ||= model.organisers.to_a
+ @organisers ||= model.organisers.to_a.sort_by { |organiser| organiser.name.to_s }
end
def month
diff --git a/app/presenters/workshop_presenter.rb b/app/presenters/workshop_presenter.rb
index e26252a4d..84148ef7b 100644
--- a/app/presenters/workshop_presenter.rb
+++ b/app/presenters/workshop_presenter.rb
@@ -31,11 +31,12 @@ def venue
@venue ||= model.host
end
+ def sponsors
+ model.sponsors.sort_by { |sponsor| sponsor.name.to_s }
+ end
+
def organisers
- @organisers ||= begin
- orgs = model.organisers.to_a
- orgs.any? ? orgs : chapter_organisers
- end
+ @organisers ||= (model.organisers.to_a.presence || chapter_organisers).sort_by { |organiser| organiser.name.to_s }
end
def attendees_checklist
diff --git a/spec/controllers/events_controller_spec.rb b/spec/controllers/events_controller_spec.rb
index 306fa616b..6b0a6b029 100644
--- a/spec/controllers/events_controller_spec.rb
+++ b/spec/controllers/events_controller_spec.rb
@@ -244,4 +244,65 @@
expect(response).to have_http_status(:ok)
end
end
+
+ describe '#load_events' do
+ let(:chapter) { Fabricate(:chapter) }
+ let(:host_sponsor) { Fabricate(:sponsor, name: 'Zulu GmbH') }
+ let(:extra_sponsor) { Fabricate(:sponsor, name: 'Alpha AG') }
+
+ def rows_for(workshops)
+ workshops.map { |w| { 'event_type' => 'Workshop', 'id' => w.id } }
+ end
+
+ it 'loads the host sponsor as workshop_host for every workshop' do
+ workshops = Fabricate.times(6, :workshop_no_sponsor, chapter:)
+ workshops.each do |workshop|
+ Fabricate(:workshop_sponsor, workshop:, sponsor: host_sponsor, host: true)
+ Fabricate(:workshop_sponsor, workshop:, sponsor: extra_sponsor, host: false)
+ end
+
+ loaded = controller.send(:load_events, rows_for(workshops))
+
+ expect(loaded.map { |e| e.workshop_host&.sponsor&.id }).to all(eq(host_sponsor.id))
+ end
+
+ it 'lists all sponsors of a workshop' do
+ workshop = Fabricate(:workshop_no_sponsor, chapter:)
+ Fabricate(:workshop_sponsor, workshop:, sponsor: host_sponsor, host: true)
+ Fabricate(:workshop_sponsor, workshop:, sponsor: extra_sponsor, host: false)
+
+ loaded = controller.send(:load_events, rows_for([workshop]))
+
+ expect(loaded.first.sponsors).to contain_exactly(host_sponsor, extra_sponsor)
+ end
+
+ it 'renders sponsors and organisers in name order' do
+ workshop = Fabricate(:workshop_no_sponsor, chapter:)
+ Fabricate(:workshop_sponsor, workshop:, sponsor: host_sponsor, host: true)
+ Fabricate(:workshop_sponsor, workshop:, sponsor: extra_sponsor, host: false)
+ anton = Fabricate(:member, name: 'Anton')
+ zora = Fabricate(:member, name: 'Zora')
+ anton.add_role :organiser, workshop
+ zora.add_role :organiser, workshop
+
+ loaded = controller.send(:load_events, rows_for([workshop]))
+ presenter = EventPresenter.decorate(loaded.first)
+
+ expect(presenter.sponsors.map(&:name)).to eq(['Alpha AG', 'Zulu GmbH'])
+ expect(presenter.organisers.map(&:name)).to eq(%w[Anton Zora])
+ end
+
+ it 'sorts organisers with blank names without raising' do
+ workshop = Fabricate(:workshop_no_sponsor, chapter:)
+ anton = Fabricate(:member, name: 'Anton')
+ anton.update_column(:name, nil)
+ anton.add_role :organiser, workshop
+ Fabricate(:member, name: 'Zora').add_role :organiser, workshop
+
+ loaded = controller.send(:load_events, rows_for([workshop]))
+ presenter = EventPresenter.decorate(loaded.first)
+
+ expect(presenter.organisers.map(&:name)).to eq([nil, 'Zora'])
+ end
+ end
end