Flamboyant loading in many ways in Rails 4

This is a simplified example of what I am trying to achieve.

  • Has_many Catalog Collection: via catalog_collections
  • Has_many Collection product: via collection_products

I have this circuit:

class Product < ActiveRecord::Base
   has_many :collection_products, :foreign_key => :product_id, :dependent => :destroy, :inverse_of => :product
   has_many :collections, :through => :collection_products, :foreign_key => :collection_id, :inverse_of => :products
end

class Catalog < ActiveRecord::Base
  has_many :catalog_collections, :foreign_key => :catalog_id, :dependent => :destroy, :inverse_of => :catalog
  has_many :collections, :through => :catalog_collections, :foreign_key => :collection_id, :inverse_of => :catalogs
end

class Collection < ActiveRecord::Base
  has_many :collection_products, :foreign_key => :collection_id, :dependent => :destroy, :inverse_of => :collection
  has_many :products, :through => :collection_products, :foreign_key => :product_id, :inverse_of => :collections

  has_many :catalog_collections, :foreign_key => :collection_id, :dependent => :destroy, :inverse_of => :collection
  has_many :catalogs, :through => :catalog_collections, :inverse_of => :collections
end

class CollectionProduct < ActiveRecord::Base
  belongs_to :collection, inverse_of: :collection_products
  belongs_to :product, inverse_of: :collection_products
end

class CatalogCollection < ActiveRecord::Base
  belongs_to :catalog, inverse_of: :catalog_collections
  belongs_to :collection, inverse_of: :catalog_collections
end

      

I am looking forward to loading associations using .includes (), this only spawns the queries I need.

cats = Catalog.includes(collections: :products)
  Catalog Load (0.6ms)  SELECT "catalogs".* FROM "catalogs"
  CatalogCollection Load (0.4ms)  SELECT "catalog_collections".* FROM "catalog_collections"  WHERE "catalog_collections"."catalog_id" IN (1)
  Collection Load (0.5ms)  SELECT "collections".* FROM "collections"  WHERE "collections"."id" IN (1)
  CollectionProduct Load (0.3ms)  SELECT "collection_products".* FROM "collection_products"  WHERE "collection_products"."collection_id" IN (1)
  Product Load (0.3ms)  SELECT "products".* FROM "products"  WHERE "products"."id" IN (1)
 => #<ActiveRecord::Relation [#<Catalog id: 1, name: "catalog1", created_at: "2014-08-20 08:59:05", updated_at: "2014-08-20 08:59:05">]>

cats.first.collections.first.products
 => #<ActiveRecord::Associations::CollectionProxy [#<Product id: 1, name: "product1", created_at: "2014-08-20 08:58:46", updated_at: "2014-08-20 08:58:46">]>

      

The problem is I have a problem with an n + 1 request, this somehow spawns more requests.

cats.first.collections.first.products.where(name: 'product1')
  Product Load (0.4ms)  SELECT "products".* FROM "products" INNER JOIN "collection_products" ON "products"."id" = "collection_products"."product_id" WHERE "collection_products"."collection_id" = ? AND "products"."name" = 'product1'  [["collection_id", 1]]
 => #<ActiveRecord::AssociationRelation [#<Product id: 1, name: "product1", created_at: "2014-08-20 08:58:46", updated_at: "2014-08-20 08:58:46">]>

      

I need to somehow request these functions using the associations we have already loaded, rather than finding everything from scratch that they are currently doing.

+3


source to share


1 answer


Extending the suggestion https://stackoverflow.com/users/419017/damien-roche in his comment

products = cats.first.collections.first.products
product_1 = products.to_a.select { |p| p.name == 'product1' }

      



Pretty likely to_a

plus is O (n) select

faster than an additional SQL query. If not, then you are already optimal.

+1


source







All Articles