Search code examples
ruby-on-railsrubyactiverecordeager-loadingbullet

Implement eager loading to stop N+1 - Rails


I currently have a page that takes 11 seconds to load. I'm using the Bullet Gem to help me find where the N+1 query is happening. Its giving my some output but I really don't know what to do with it. Here is the output from Bullet:

GET /events/1679/dashboard
USE eager loading detected
  RSVP => [:tickets]
  Add to your finder: :includes => [:tickets]
Call stack
  /Users/cameronbass/Desktop/Work/blackbird-rsvp/app/decorators/rsvp_decorator.rb:54:in `tickets?'
  /Users/cameronbass/Desktop/Work/blackbird-rsvp/app/views/accepted_rsvps/_list.html.erb:33:in `block in _app_views_accepted_rsvps__list_html_erb___1211423417683052584_70339569780320'

And it's telling me to put it on this line

def tickets?
  rsvp.tickets.any?
end

Here is the association:

has_many :tickets, through: :attendees

attendee.rb

has_one :ticket

Solution

  • Bullet points you to the place where it detected multiple calls of the same association, not to the place where you should add eager loading.

    Somewhere in the _list.html.erb template you probably traverse your RSVPs (whatever that is) and for each RSVP you are trying to determine whether it has any ticket or not by calling the tickets association.

    Bullet advices you to add include(:tickets) to the finder which sets up the variable for RSVPs (probably somewhere in your AcceptedRSVPs controller) that you traverse in the template. Once that is done, there won't be an SQL run for each RSVP to find out its tickets and thus you'll get rid of the N+1 problem.