Skip to content
Advertisement

Rails – deeply nested joins with ActiveRecord

I occasionally need to do a join in my app that goes across multiple tables, but haven’t quite figured out how to do this for more than 3 tables:

class Store < ApplicationRecord
  has_many :products
end

class Product < ApplicationRecord
  belongs_to :store
  has_many :product_variants
end

class ProductVariant < ApplicationRecord
  belongs_to :product
  has_many :order_list_items
end

class OrderListItem < ApplicationRecord
  belongs_to :product_variant
  has_many :consumers
end

class Consumer < ApplicationRecord
  belongs_to :order_list_item
end

Currently I’m ready to go:

Store.joins(products: [{ product_variants: :order_list_items }])

What I would like to do now is to join every consumer that belongs to an OrderListItem.

However, when I try the following:

Store.joins(products: [{ product_variants: :order_list_items }], order_list_items: [:consumers])

I get the error:

(Object doesn't support #inspect)

With the following two attempts also the same error:

Store.joins(products: [{ product_variants: :order_list_items }, order_list_items: [:consumers]])
Store.joins(products: [{ product_variants: :order_list_items }], order_list_items: [:consumers])

I have set the associations correctly and order_list_item.consumers and consumer.order_list_items and order_list_item.product_variant as well as product_variant.order_list_items work fine.

I have also not overridden initialize on any model.

The working SQL looks like this:

SELECT stores.id, products.id as product_id, product_variants.id as product_variant_id, order_list_items.id as list_item_id, consumers.id as consumer_id
FROM stores
INNER JOIN products ON products.store_id = stores.id
INNER JOIN product_variants on product_variants.product_id = products.id
INNER JOIN order_list_items on order_list_items.product_variant_id = product_variants.id
INNER JOIN consumers on consumers.order_list_item_id = order_list_items.id;

Thanks for any tips.

Advertisement

Answer

Try this

Store.joins(products: [product_variants: [order_list_items: :consumers]])

Below is the sql query

SELECT "stores".* FROM "stores" 
INNER JOIN "products" 
ON "products"."store_id" = "stores"."id" 
INNER JOIN "product_variants" 
ON "product_variants"."product_id" = "products"."id" 
INNER JOIN "order_list_items" 
ON "order_list_items"."product_variant_id" = "product_variants"."id" 
INNER JOIN "consumers" 
ON "consumers"."order_list_item_id" = "order_list_items"."id";
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement