Here's what happens:
I have in my controller:
@products = Spree::Product.all_active
And in the model:
Spree::Product.class_eval do
def self.all_active
includes(:master)
.where('available_on IS NULL OR available_on < ?', Time.now).where(deleted_at: nil)
end
end
And in the view I'm calling something that will look like this:
@products.each do |product|
product.images.each do |image|
image.attachment.url(:product)
end
end
The log is showing something along the lines like this for every single product:
Spree::Image Load (2.6ms) SELECT "spree_assets".* FROM "spree_assets" WHERE "spree_assets"."type" IN ('Spree::Image') AND "spree_assets"."viewable_id" = $1 AND "spree_assets"."viewable_type" = $2 ORDER BY "spree_assets"."position" ASC [["viewable_id", 9], ["viewable_type", "Spree::Variant"]]
Spree::Price Load (0.3ms) SELECT "spree_prices".* FROM "spree_prices" WHERE "spree_prices"."variant_id" = $1 AND "spree_prices"."currency" = 'USD' LIMIT 1 [["variant_id", 9]]
CACHE (0.3ms) SELECT "spree_zone_members".* FROM "spree_zone_members" WHERE "spree_zone_members"."zone_id" = $1 [["zone_id", 2]]
CACHE (0.0ms) SELECT "spree_countries".* FROM "spree_countries" WHERE "spree_countries"."id" IN (204, 49)
CACHE (0.2ms) SELECT "spree_shipping_methods".* FROM "spree_shipping_methods" INNER JOIN "spree_shipping_methods_zones" ON "spree_shipping_methods"."id" = "spree_shipping_methods_zones"."shipping_method_id" WHERE "spree_shipping_methods"."deleted_at" IS NULL AND "spree_shipping_methods_zones"."zone_id" = $1 [["zone_id", 2]]
CACHE (0.0ms) SELECT "spree_calculators".* FROM "spree_calculators" WHERE "spree_calculators"."calculable_type" = 'Spree::ShippingMethod' AND "spree_calculators"."calculable_id" IN (3, 2, 1)
(0.8ms) SELECT COUNT(*) FROM "spree_assets" WHERE "spree_assets"."type" IN ('Spree::Image') AND "spree_assets"."viewable_id" = $1 AND "spree_assets"."viewable_type" = $2 [["viewable_id", 1], ["viewable_type", "Spree::Variant"]]
I also have the bullet gem installed and it is recommending me to do:
N+1 Query detected
Spree::Variant => [:images]
Add to your finder: :include => [:images]
N+1 Query detected
Spree::Variant => [:default_price]
Add to your finder: :include => [:default_price]
I'm not sure where to place this .includes
. to find out where Spree::Variant
is being called I went to the Rails console:
2.0.0-p481 :001 > Spree::Product.first
Spree::Product Load (1.8ms) SELECT "spree_products".* FROM "spree_products" WHERE "spree_products"."deleted_at" IS NULL ORDER BY "spree_products"."id" ASC LIMIT 1
=> #<Spree::Product id: 1, name: "Ruby on Rails Tote", description: "Debitis facilis impedit natus eos qui vero. Ut qua...", available_on: "2014-07-04 05:44:50", deleted_at: nil, slug: "ruby-on-rails-tote", meta_description: nil, meta_keywords: nil, tax_category_id: 1, shipping_category_id: 1, created_at: "2014-07-04 05:44:51", updated_at: "2014-07-04 05:45:30">
2.0.0-p481 :002 > Spree::Product.first.images
Spree::Product Load (0.8ms) SELECT "spree_products".* FROM "spree_products" WHERE "spree_products"."deleted_at" IS NULL ORDER BY "spree_products"."id" ASC LIMIT 1
Spree::Variant Load (1.0ms) SELECT "spree_variants".* FROM "spree_variants" WHERE "spree_variants"."deleted_at" IS NULL AND "spree_variants"."product_id" = $1 AND "spree_variants"."is_master" = 't' LIMIT 1 [["product_id", 1]]
Spree::Image Load (0.8ms) SELECT "spree_assets".* FROM "spree_assets" WHERE "spree_assets"."type" IN ('Spree::Image') AND "spree_assets"."viewable_id" = $1 AND "spree_assets"."viewable_type" = $2 ORDER BY "spree_assets"."position" ASC [["viewable_id", 1], ["viewable_type", "Spree::Variant"]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Spree::Image id: 21, viewable_id: 1, viewable_type: "Spree::Variant", attachment_width: 360, attachment_height: 360, attachment_file_size: 31490, position: 1, attachment_content_type: "image/jpeg", attachment_file_name: "ror_tote.jpeg", type: "Spree::Image", attachment_updated_at: "2014-07-04 05:45:28", alt: nil, created_at: "2014-07-04 05:45:29", updated_at: "2014-07-04 05:45:29">, #<Spree::Image id: 22, viewable_id: 1, viewable_type: "Spree::Variant", attachment_width: 360, attachment_height: 360, attachment_file_size: 28620, position: 2, attachment_content_type: "image/jpeg", attachment_file_name: "ror_tote_back.jpeg", type: "Spree::Image", attachment_updated_at: "2014-07-04 05:45:29", alt: nil, created_at: "2014-07-04 05:45:30", updated_at: "2014-07-04 05:45:30">]>
Where would I add :images
and :default_price
within this context?
try:
Spree::Product.class_eval do
def self.all_active
includes(master: { products: :images } )
.where('available_on IS NULL OR available_on < ?', Time.now).where(deleted_at: nil)
end
end
includes can be used to fetch multiple models, nested or not.