Break up the one-query-of-doom

The single query was producing a tremendously large ActiveRecord allocation.

While this isn't nearly as cool as one query, it's still a significant
reduction in SQL trips, and now has the bonus of only loading what is
actually going to be displayed.
This commit is contained in:
James Mason 2017-12-21 19:06:36 -08:00
parent 754d201b01
commit fa55224163
26 changed files with 181 additions and 165 deletions

View file

@ -9,34 +9,48 @@ class ConferencesController < ApplicationController
end
def show
# load conference with header content
@conference = Conference.unscoped.eager_load(
:organization,
:splashpage,
:registration_period,
:tickets,
:confirmed_tracks,
:call_for_events,
:event_types,
:program,
:call_for_tracks,
:lodgings,
:call_for_booths,
:confirmed_booths,
:sponsors,
:call_for_sponsors,
:registration_period,
:contact,
venue: [:commercial],
highlighted_events: [:speakers],
sponsorship_levels: [:sponsors]
).order(
'sponsorship_levels.position ASC',
'sponsors.name',
'tracks.name',
'booths.title',
'lodgings.name',
'tickets.price_cents'
venue: :commercial
).find_by(conference_finder_conditions)
authorize! :show, @conference
authorize! :show, @conference # TODO: reduce the 10 queries performed here
splashpage = @conference.splashpage
if splashpage.include_cfp
cfps = @conference.program.cfps
@call_for_events = cfps.find { |call| call.cfp_type == 'events' }
if @call_for_events.try(:open?)
@event_types = @conference.event_types.pluck(:title)
@track_names = @conference.confirmed_tracks.pluck(:name).sort
end
@call_for_tracks = cfps.find { |call| call.cfp_type == 'tracks' }
end
if splashpage.include_program
@highlights = @conference.highlighted_events.eager_load(:speakers)
if splashpage.include_tracks
@tracks = @conference.confirmed_tracks.eager_load(
:room
).order('tracks.name')
end
if splashpage.include_booths
@booths = @conference.confirmed_booths.order('title')
end
end
if splashpage.include_registrations || splashpage.include_tickets
@tickets = @conference.tickets.order('price_cents')
end
if splashpage.include_lodgings
@lodgings = @conference.lodgings.order('name')
end
if splashpage.include_sponsors
@sponsorship_levels = @conference.sponsorship_levels.eager_load(
:sponsors
).order('sponsorship_levels.position ASC', 'sponsors.name')
end
end
private

View file

@ -141,7 +141,7 @@ module ApplicationHelper
hint: 'The people responsible for the booth. You can only select existing users.'
end
def event_types(conference)
def event_types_sentence(conference)
conference.event_types.map { |et| et.title.pluralize }.to_sentence
end

View file

@ -1,8 +1,7 @@
module ConferenceHelper
# Return true if only call_for_papers or call_for_tracks is open
def one_call_open(conference)
conference.call_for_events.try(:open?) ^
conference.call_for_tracks.try(:open?)
def one_call_open(*calls)
calls.one? { |call| call.try(:open?) }
end
# URL for sponsorship emails

View file

@ -46,7 +46,6 @@ class Conference < ApplicationRecord
has_many :campaigns, dependent: :destroy
has_many :commercials, as: :commercialable, dependent: :destroy
has_many :subscriptions, dependent: :destroy
has_one :call_for_sponsors, -> { where(cfp_type: 'sponsors') }, through: :program, source: :cfps
has_one :call_for_events, -> { where(cfp_type: 'events') }, through: :program, source: :cfps
has_one :call_for_booths, -> { where(cfp_type: 'booths') }, through: :program, source: :cfps
has_one :call_for_tracks, -> { where(cfp_type: 'tracks') }, through: :program, source: :cfps

View file

@ -21,7 +21,7 @@
%dt
Event types:
%dd
= event_types(@conference)
= event_types_sentence(@conference)
%dt
Tracks:
%dd

View file

@ -22,7 +22,7 @@
%dt
Event types:
%dd
= event_types(@conference)
= event_types_sentence(@conference)
%dt
Tracks:
%dd

View file

@ -2,7 +2,7 @@
.col-md-12
%h3.text-center Booths
.row.row-centered
- conference.confirmed_booths.to_a.sort_by!(&:title).each do |booth|
- booths.each do |booth|
.col-md-2.col-sm-2.col-centered.col-top.booth
%a.thumbnail{ href: '#',
data: { toggle: 'modal', target: "#modal-booth-#{booth.id}" } }

View file

@ -5,10 +5,12 @@
%section#call
.container
.row
- if one_call_open(conference)
- if one_call_open(call_for_events, call_for_tracks)
.col-md-3.col-sm-3.hidden-xs &nbsp;
- if conference.call_for_events.try(:open?)
= render 'call_for_papers', conference: conference
- if call_for_events.try(:open?)
= render 'call_for_papers', conference_id: conference.short_title,
call: call_for_events, event_types: event_types, tracks: tracks
.col-md-2.col-sm-2 &nbsp;
- if conference.call_for_tracks.try(:open?)
= render 'call_for_tracks', conference: conference
- if call_for_tracks.try(:open?)
= render 'call_for_tracks', conference_id: conference.short_title,
call: call_for_tracks

View file

@ -1,30 +1,27 @@
- cache [conference, conference.call_for_events, conference.confirmed_tracks,
'#splash#callforpapers'] do
- cache [conference_id, call, event_types, tracks, '#splash#callforpapers'] do
.col-md-5.col-sm-5.text-center
%h2
Call for Papers
%p.lead
We are now accepting proposals for sessions!
%p
- if conference.event_types.any?
- if event_types.any?
You can submit proposals for
%span.notranslate
= event_types(conference) + '.'
- if conference.confirmed_tracks.any?
= event_types.map(&:pluralize).to_sentence + '.'
- if tracks.any?
Proposals should fit in one of the
%span.notranslate
= pluralize(conference.confirmed_tracks.length, 'track') + ':'
= tracks(conference) + '.'
- if conference.call_for_events.try(:open?)
The submission period is open
%em.notranslate
= date_string(conference.call_for_events.start_date,
conference.call_for_events.end_date) + '.'
%b
You have
= pluralize(conference.call_for_events.remaining_days, 'day')
left!
= pluralize(tracks.length, 'track') + ':'
= tracks.to_sentence + '.'
The submission period is open
%em.notranslate
= date_string(call.start_date, call.end_date) + '.'
%b
You have
= pluralize(call.remaining_days, 'day')
left!
%p.cta-button
= link_to "Submit your proposal now",
conference_program_proposals_path(conference.short_title),
conference_program_proposals_path(conference_id),
class: 'btn btn-success btn-lg text-center'

View file

@ -1,4 +1,4 @@
- cache [conference, conference.call_for_tracks, '#splash#callfortracks'] do
- cache [conference_id, call, '#splash#callfortracks'] do
.col-md-5.col-sm-5.text-center
%h2
Call for Tracks
@ -8,13 +8,12 @@
Would you like to host a mini-summit, sub-conference, or hack space?
The submission period for track requests is open
%em
= date_string(conference.call_for_tracks.start_date,
conference.call_for_tracks.end_date) + '.'
= date_string(call.start_date, call.end_date) + '.'
%b
You have
= pluralize(conference.call_for_tracks.remaining_days, 'day')
= pluralize(call.remaining_days, 'day')
left!
%p.cta-button
= link_to("Submit your request for track",
conference_program_tracks_path(conference.short_title),
conference_program_tracks_path(conference_id),
class: 'btn btn-success btn-lg text-center')

View file

@ -1,4 +1,4 @@
- cache [conference, conference.venue, '#splash#header'] do
- cache [conference, venue, '#splash#header'] do
#banner
.container
.row
@ -18,14 +18,13 @@
= date_string(conference.start_date, conference.end_date)
- if conference.venue
%span.venue.text-nowrap
- if conference.venue.website
= sanitize link_to(conference.venue.name,
conference.venue.website)
- if venue.website
= sanitize link_to(venue.name, venue.website)
- else
= conference.venue.city
- if conference.venue.country_name != 'US'
= venue.city
- if venue.country_name != 'US'
&bull;
= conference.venue.country_name
= venue.country_name
- unless conference.description.blank?
%section#about

View file

@ -5,10 +5,10 @@
.row
.col-md-12
.row.row-centered
- conference.highlighted_events.each do |event|
- highlights.each do |event|
- speaker = event.speakers_ordered.first
.col-md-3.col-sm-3.col-centered.col-top.highlights
= link_to(conference_program_proposal_path(conference.short_title,
= link_to(conference_program_proposal_path(conference_id,
event),
class: 'thumbnail') do
= image_tag speaker.gravatar_url(size: 300),

View file

@ -2,21 +2,21 @@
%li
%a.smoothscroll{ href: '#lodging' } Lodging
- cache [conference.venue, conference.lodgings, '#splash#lodging'] do
- cache [venue, lodgings, '#splash#lodging'] do
%section#lodging
.container
.row
.col-md-12.text-center
%h2
Where to stay
- if conference.venue
- if venue
in
= conference.venue.city
= venue.city
%p.lead
We recommend the following accommodations for your visit.
.row.row-centered
- conference.lodgings.each do |lodging|
- lodgings.each do |lodging|
.col-md-4.col-sm-4.col-centered.col-top
.thumbnail
- if lodging.picture?

View file

@ -2,8 +2,7 @@
%li
%a.smoothscroll{ href: '#program' } Program
- cache [@confererence, @conference.confirmed_tracks,
@conference.confirmed_booths,'#splash#program'] do
- cache [conference, highlights, tracks, booths, '#splash#program'] do
%section#program
.container
.row
@ -13,16 +12,17 @@
= conference.title
has the most awesome program ever!
- if conference.highlighted_events.any?
= render 'highlights', conference: conference
- unless highlights.blank?
= render 'highlights', conference_id: conference.short_title,
highlights: highlights
- if conference.splashpage.include_tracks
- if conference.confirmed_tracks.any?
= render 'tracks', conference: conference
- unless tracks.blank?
= render 'tracks', tracks: tracks
- if conference.splashpage.include_booths
- if conference.confirmed_booths.any?
= render 'booths', conference: conference
- unless booths.blank?
= render 'booths', booths: booths
- if conference.program.try(:schedule_public?)
.row
@ -32,6 +32,7 @@
class: 'btn btn-success btn-lg') do
Full Schedule
- conference.confirmed_booths.each do |booth|
- content_for :modals do
= render 'modal_description', object: booth
- unless booths.blank?
- booths.each do |booth|
- content_for :modals do
= render 'modal_description', object: booth

View file

@ -2,8 +2,7 @@
%li
%a.smoothscroll{ href: '#registration' } Registration
- cache [conference.registration_period, conference.tickets,
'#splash#registration'] do
- cache [conference, registration_period, tickets, '#splash#registration'] do
%section#registration
.container
.row
@ -12,23 +11,23 @@
- if conference.registration_limit_exceeded?
%p
Sorry, the conference registration limit has exceeded
- elsif conference.tickets.empty?
- elsif tickets.empty?
%p.lead
Going to
= conference.short_title
is free of charge.
%p
We only ask you to register yourself before
= date_string(conference.registration_period.end_date)
= date_string(registration_period.end_date)
so we can plan for the right amount of people.
%p.cta-button
- else
%p
The registration period is open
= date_string(conference.registration_period.start_date,
conference.registration_period.end_date)
= date_string(registration_period.start_date,
registration_period.end_date)
- if conference.registration_open?
%p.cta-button
= link_to('Register Now',
new_conference_conference_registration_path(conference.short_title),
new_conference_conference_registration_path(conference_id),
class: 'btn btn-lg btn-success')

View file

@ -1,20 +1,20 @@
- cache [conference.contact, '#splash#social'] do
- cache [contact, '#splash#social'] do
%section#social-media
.container
.row
.col-md-12.text-center
- unless conference.contact.facebook.blank?
= link_to "#{ conference.contact.facebook }" do
- unless contact.facebook.blank?
= link_to "#{ contact.facebook }" do
%i.fa.fa-facebook-square.fa-4x
- unless conference.contact.twitter.blank?
= link_to "#{ conference.contact.twitter }" do
- unless contact.twitter.blank?
= link_to "#{ contact.twitter }" do
%i.fa.fa-twitter.fa-4x
- unless conference.contact.instagram.blank?
= link_to "#{ conference.contact.instagram }" do
- unless contact.instagram.blank?
= link_to "#{ contact.instagram }" do
%i.fa.fa-instagram.fa-4x
- unless conference.contact.googleplus.blank?
= link_to "#{ conference.contact.googleplus }" do
- unless contact.googleplus.blank?
= link_to "#{ contact.googleplus }" do
%i.fa.fa-google-plus-square.fa-4x
- unless conference.contact.email.blank?
= mail_to "#{ conference.contact.email }" do
- unless contact.email.blank?
= mail_to "#{ contact.email }" do
%i.fa.fa-envelope-o.fa-4x

View file

@ -2,11 +2,10 @@
%li
%a.smoothscroll{ href: '#sponsors' } Sponsors
- cache [conference, conference.sponsors, conference.sponsorship_levels,
conference.try(:call_for_sponsors), '#splash#sponsors'] do
- cache [conference, sponsorship_levels, '#splash#sponsors'] do
%section#sponsors
.container
- conference.sponsorship_levels.each do |sponsorship_level|
- sponsorship_levels.each do |sponsorship_level|
- if sponsorship_level.sponsors.any?
.row.text-center
%h3
@ -17,19 +16,21 @@
.col-md-4.col-sm-4.col-centered.col-top
%a{ href: '#', data: { toggle: 'modal',
target: "#modal-sponsor-#{sponsor.id}" } }
= image_tag get_logo(sponsor),
class: ['img-responsive', 'img-sponsor',
"img-sponsor-#{sponsorship_level.position}"],
title: sponsor.name
- if sponsor.logo_file_name
= image_tag get_logo(sponsor),
class: ['img-responsive', 'img-sponsor',
"img-sponsor-#{sponsorship_level.position}"],
title: sponsor.name
- else
%h4.text-center= sponsor.name
- if conference.call_for_sponsors.try(:open?)
.row
.col-md-12
%h3.text-center
Want to sponsor?
= link_to(sponsorship_mailto(conference)) do
Contact us!
.row
.col-md-12
%h3.text-center
Want to sponsor?
= link_to(sponsorship_mailto(conference)) do
Contact us!
- conference.sponsors.each do |sponsor|
- sponsorship_levels.collect(&:sponsors).flatten.each do |sponsor|
- content_for :modals do
= render 'modal_description', object: sponsor

View file

@ -2,7 +2,7 @@
%li
%a.smoothscroll{ href: '#tickets' } Tickets
- cache [conference, conference.tickets, '#splash#tickets'] do
- cache [conference, tickets, '#splash#tickets'] do
%section#tickets
.container
.row
@ -11,7 +11,7 @@
Support
= conference.title
.row.row-centered
- conference.tickets.each do |ticket|
- tickets.each do |ticket|
.col-md-3.col-sm-3.col-centered.col-top
= link_to(conference_tickets_path(conference.short_title),
class: 'thumbnail') do

View file

@ -2,7 +2,7 @@
.col-md-12
%h3.text-center Tracks
.row.row-centered
- conference.confirmed_tracks.to_a.sort_by!(&:name).each do |track|
- tracks.each do |track|
.col-md-3.col-sm-3.col-centered.col-top.track
.thumbnail
.caption

View file

@ -3,42 +3,41 @@
%a.smoothscroll{ href: '#venue' } Venue
%section#venue
- if conference.venue.location?
= render '/conferences/venue_map', conference: conference
- if venue.location?
= render '/conferences/venue_map', venue: venue
- else
- cache [conference.venue, conference.venue.commercial, '#splash#venue'] do
- cache [venue, commercial, '#splash#venue'] do
.container
.row
.col-md-6
.thumbnail#venue-pic
- if commercial = conference.venue.commercial
- if commercial
.flexvideo{ id: "resource-content-#{commercial.id}" }
= render 'shared/media_item',
commercial: commercial
- elsif conference.venue.picture?
= image_tag conference.venue.picture.url,
title: conference.venue.name, class: "img-responsive"
- elsif venue.picture?
= image_tag venue.picture.url,
title: venue.name, class: "img-responsive"
- else
%p.text-center
%span.fa.fa-university.fa-5x
.caption
%h3.text-center
= conference.venue.name
- unless conference.venue.description.blank?
= markdown(conference.venue.description)
= venue.name
- unless venue.description.blank?
= markdown(venue.description)
.col-md-6
%h2
= conference.venue.city
= venue.city
\/
= conference.venue.country_name
= venue.country_name
%address
= conference.venue.street
= venue.street
%br
= conference.venue.postalcode + ','
= conference.venue.city
= venue.postalcode + ','
= venue.city
%br
= conference.venue.country_name
- if conference.venue.website
= venue.country_name
- if venue.website
%br
= sanitize link_to(h(conference.venue.website),
h(conference.venue.website))
= sanitize link_to(h(venue.website), h(venue.website))

View file

@ -1,13 +1,13 @@
#map{ style: "height: 500px;" }
- content_for(:script_body) do
- marker = escape_javascript(render '/conferences/venue_map_marker',
venue: conference.venue)
venue: venue)
:javascript
// create a map in the "map" div, set the view to a given place and zoom
var map = L.map('map', { scrollWheelZoom: false }).setView(
[
#{conference.venue.latitude.to_f + 0.05},
#{h(conference.venue.longitude)}
#{venue.latitude.to_f + 0.05},
#{h(venue.longitude)}
], 11);
// add an OpenStreetMap tile layer
L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
@ -20,8 +20,8 @@
// add a marker in the given location, attach some popup content to it
// and open the popup
L.marker([
#{h conference.venue.latitude},
#{h conference.venue.longitude}
#{h venue.latitude},
#{h venue.longitude}
]).addTo(map)
.bindPopup("#{marker}")
.openPopup();

View file

@ -12,35 +12,43 @@
#splash
-# header/description
= render 'header', conference: @conference
= render 'header', conference: @conference, venue: @conference.venue
-# calls for content, or program
- if @conference.splashpage.include_cfp
= render 'call_for_content', conference: @conference
= render 'call_for_content', conference: @conference,
call_for_events: @call_for_events, call_for_tracks: @call_for_tracks,
event_types: @event_types, tracks: @track_names
- if @conference.splashpage.include_program
= render 'program', conference: @conference
= render 'program', conference: @conference, tracks: @tracks,
highlights: @highlights, booths: @booths
-# attendance/registration
- if @conference.splashpage.include_registrations
- if @conference.registration_open?
= render 'registration', conference: @conference
= render 'registration', conference: @conference,
registration_period: @conference.registration_period,
tickets: @tickets, conference_id: @conference_id.short_title
- if @conference.splashpage.include_tickets && @conference.tickets.any?
= render 'tickets', conference: @conference
= render 'tickets', conference: @conference, tickets: @tickets
-# geo
- if @conference.splashpage.include_venue && @conference.venue
= render 'venue', conference: @conference
= render 'venue', conference: @conference, venue: @conference.venue,
commercial: @conference.venue.commercial
- if @conference.splashpage.include_lodgings && @conference.lodgings.any?
= render 'lodging', conference: @conference
= render 'lodging', venue: @conference.venue, lodgings: @lodgings
-# sponsorship
- if @conference.splashpage.include_sponsors
= render 'sponsors', conference: @conference
= render 'sponsors', conference: @conference,
sponsorship_levels: @sponsorship_levels
-# footer
- if @conference.splashpage.include_social_media
- if @conference.contact.has_social_media?
= render 'social_media', conference: @conference
= render 'social_media', contact: @conference.contact
= render 'footer'
= yield :modals

View file

@ -1,7 +1,7 @@
%p.lead
- if @program.event_types.any?
You can submit proposals for
= "#{event_types(@conference)}."
= "#{event_types_sentence(@conference)}."
- if @program.tracks.confirmed.cfp_active.any?
Proposals should fit in one of the
= "#{pluralize(@program.tracks.confirmed.cfp_active.count, 'track')}:"

View file

@ -13,7 +13,7 @@ feature Splashpage do
visit admin_conference_splashpage_path(conference.short_title)
click_link 'Create Splashpage'
click_button 'Save Splashpage'
click_button 'Save Changes'
expect(flash).to eq('Splashpage successfully created.')
expect(current_path).to eq(admin_conference_splashpage_path(conference.short_title))
@ -28,7 +28,7 @@ feature Splashpage do
click_link 'Edit'
check('Make splash page public')
click_button 'Save Splashpage'
click_button 'Save Changes'
expect(flash).to eq('Splashpage successfully updated.')
expect(current_path).to eq(admin_conference_splashpage_path(conference.short_title))

View file

@ -233,18 +233,18 @@ feature 'Version' do
scenario 'display changes in splashpages', feature: true, versioning: true, js: true do
visit admin_conference_splashpage_path(conference.short_title)
click_link 'Create Splashpage'
click_button 'Save Splashpage'
click_button 'Save Changes'
click_link 'Edit'
uncheck('Display program')
uncheck('Display call for papers and call for tracks information on splashpage, while open')
uncheck('Display venue')
uncheck('Display the program')
uncheck('Display call for papers and call for tracks, while open')
uncheck('Display the venue')
uncheck('Display tickets')
uncheck('Display the lodgings')
uncheck('Display sponsors')
uncheck('Display social media')
uncheck('Display social media links')
check('Make splash page public?')
click_button 'Save Splashpage'
click_button 'Save Changes'
splashpage_id = conference.splashpage.id
click_link 'Delete'

View file

@ -6,7 +6,7 @@ describe ConferenceHelper, type: :helper do
describe '#one_call_open' do
it 'is falsey if neither call is open' do
expect(one_call_open(conference)).to be_falsey
expect(one_call_open(*conference.program.cfps)).to be_falsey
end
it 'is truthy if call_for_papers is open' do
@ -17,8 +17,7 @@ describe ConferenceHelper, type: :helper do
start_date: conference.start_date,
end_date: conference.end_date
)
expect(one_call_open(conference)).to be_truthy
expect(one_call_open(*conference.program.cfps)).to be_truthy
end
it 'is truthy if call_for_tracks is open' do
@ -30,7 +29,7 @@ describe ConferenceHelper, type: :helper do
end_date: conference.end_date
)
expect(one_call_open(conference)).to be_truthy
expect(one_call_open(*conference.program.cfps)).to be_truthy
end
it 'is falsey if both calls are open' do
@ -49,7 +48,7 @@ describe ConferenceHelper, type: :helper do
end_date: conference.end_date
)
expect(one_call_open(conference)).to be_falsey
expect(one_call_open(*conference.program.cfps)).to be_falsey
end
end