Question

I have this model:

class Product < ActiveRecord::Base
  belongs_to :shop

  has_many :categories_products, dependent: :destroy, autosave: true
  has_many :categories, through: :categories_products

  has_many :favorite_products, dependent: :destroy
  has_many :users, through: :favorite_products

  scope :by_shop_category, ->(shop_id, category_id) { eager_load(:categories_products).where(shop_id: shop_id, categories_products: {category_id: category_id}) }
  scope :by_category, ->(category_id) { eager_load(:categories_products).where(categories_products: {category_id: category_id}) }

I have these 2 queries:

favorite_products = Product.where(id: current_user.product_ids).by_category(@category.id)
favorite_shop_products = Product.by_shop_category(current_user.shop_ids, @category.id)

The first returns all the products the current user has favorited from a certain category. The second returns all the products from a certain category from all shops the current user has favorited.

Obviously if a user has favorited a product belonging to a shop that they've favorited then the product will appear in both sets.

What's the cleanest performant way to come up with a set of unique results?

Was it helpful?

Solution 2

I landed on this as the simplest most performant option because it uses SQL to make the exclusion:

favorite_products = Product.where(id: current_user.product_ids).by_category(@category.id)
favorite_shop_products = Product.where.not(id: current_user.product_ids).by_shop_category(current_user.shop_ids, @category.id)
@products = favorite_products + favorite_shop_products

OTHER TIPS

favorite_products | favorite_shop_products

uses the Array union operator to combine the two sets and eliminate duplicates. This may or may not be performant depending on the size of the result sets.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top