Kyoumu
Kyoumu

Reputation: 55

Eager-loading with many-to-many relationship

I have 3 models:

class Thing < ActiveRecord::Base
  has_many :products
  has_many :shops, through: :products
end

class Product < ActiveRecord::Base
  belongs_to :thing
  belongs_to :shop
end

class Shop < ActiveRecord::Base
  has_many :products
  has_many :things, through: :products
end

Shop sales many things. Every shop has its own page with the list of its things. Products table has shop_id, thing_id, things quantity and thing price. Here is controller:

def show
  @shop = Shop.find(params[:id])
end

And view:

<% @shop.things.each do |thing| %>
  <%= link_to thing.name, shop_thing_path(id: thing.id, shop_id: @shop.id) %><br>
  <%= thing.products.find_by(shop_id: @shop.id).price %><br>
  <%= thing.products.find_by(shop_id: @shop.id).quantity %>
<% end %>

I can't understand how to eager load this right. Now i get N * 2 queries (N = things count):

SELECT "products".* FROM "products" WHERE "products"."thing_id" = ? AND "products"."shop_id" = 1 LIMIT 1

Upvotes: 0

Views: 769

Answers (2)

Kyoumu
Kyoumu

Reputation: 55

I tried to go from another point and use @products instead of @shop.things:

Controller:

def show
  @shop = Shop.find(params[:id])
  @products = @shop.products.includes(:thing).joins(:thing)
end

View

<% @products.each do |product| %>
  <tr>
    <td><%= link_to product.thing.name, shop_thing_path(id: product.thing_id, shop_id: product.shop_id) %></td>
    <td><%= product.price %></td>
    <td><%= product.quantity %></td>
  </tr>
<% end %>

Now that works. But i still can't understand why

def show
  @shop = Shop.includes(:things).find(params[:id])
end

doesn't work.

Upvotes: 0

Rafal
Rafal

Reputation: 2576

def show @shop = Shop.includes(:things).find(params[:id]) end

Here is the documentation related to eager loading.

http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

Upvotes: 1

Related Questions