2
votes

I'm using the bullet gem to find out what n+1 query problems my app has, and it turns out I have 3 issues:

user: Rashed N+1 Query detected Sale => [:shop] Add to your finder: :includes => [:shop] user: Rashed N+1 Query detected Shop => [:malls] Add to your finder: :includes => [:malls] user: Rashed N+1 Query detected Shop => [:categories] Add to your finder: :includes => [:categories]

The problem is i'm not really sure how to go about solving the problem using includes because of how my models are associated with eachother. I have 4 models, Sale, Shop, Mall, and Category. These are the associations for my models:

class Shop < ActiveRecord::Base
    has_many :categorizations
    has_many :categories, :through => :categorizations
    has_many :mall_shops
    has_many :malls, :through => :mall_shops
    has_many :sales, dependent: :destroy
end

class Sale < ActiveRecord::Base
    belongs_to :shop
end

class Mall < ActiveRecord::Base
    has_many :mall_shops
    has_many :shops, :through => :mall_shops
    has_many :sales, :through => :shops
end

class Category < ActiveRecord::Base
    has_many :categorizations
    has_many :shops, :through => :categorizations
    has_many :sales, :through => :shops
end

In my Sale index page, im displaying all the Sales records, and each sale record belongs to a shop, and each shop has many categories and many malls. For every Sale record displayed im iterating through all the malls and categories that that Sale's Shop belong to (for filtering purposes). This is the relevant code in my Sale index page:

 <% @sales.each do |sale| %>
  <div class="<% sale.shop.malls.each do |m| %> mall<%= m.id %><% end %><% sale.shop.categories.each do |c| %> category<%= c.id %><% end %>">

.
.

end

And my Sale's Controller:

class SalesController < ApplicationController
 def index
    @malls = Mall.all.order('name ASC')
    @categories = Category.all.order('category_type ASC')
    @shops = Shop.all
    @sales = Sale.where('offer_end >= ?', Date.today).order('offer_end ASC')
  end
end

So what would be the best way to solve the n+1 query issue I have? to get a better idea of my app this is the website im building: www.shopwatchkw.com

1

1 Answers

4
votes

In the controller, try this:

@sales = Sale.includes(shop: [:categories, :malls])
             .where('offer_end >= ?', Date.today)
             .order('offer_end ASC')

Basically, you're starting with your top-level model and eager-loading its children via the includes statement. Bullet was telling you to add .includes(:shop) and then, after that, it would probably tell you the same thing about :categories and :mails, which are subqueries on Shop, as you describe.

Read more on eager loading in Rails.