Lucian Tarna
Lucian Tarna

Reputation: 1827

Eager Loading Optimization in ruby on rails

I have a product that has_many Variants. And a variant belongs to a product. I want to display the name of the product(which can be found in Product) and the price and quantity(which can be found in Variants).

Product table:
 -id
 -title
 -description

Variants table:
 - id
 - is_active(boolean)
 - price
 - quantity
 - product_id

This is how the table looks like. And this is my attempt

  def index

    @products =Product.all
    @display = []
    @products.each do |product|
      @children = product.variants.where(is_active: true).order(:price).
                                   select(:id,:price,:quantity).first

      if @children.present?
      @display << {
                   id: product.id,
                    title: product.title,
                    description: product.description,
                    price:  @children.price,
                    quantity:  @children.quantity,
                    variant_id:  @children.id
                  }
      end
    end

    @display = Kaminari.paginate_array(@display).page(params[:page])

  end

I need to optimize this to the maximum. Which brings me to my first question. How can I optimize this better .
And my 2nd question why when I do @products = Product.all.includes(:variants) it will actually increase the loading time instead of lowering it since I do get the variants for every product in that iteration over the whole @products array(so it should count as an N+1, I get products for each product I get variants)? Is spliting my array of @products in 4 and making 4 threads populate display a good idea?

Upvotes: 1

Views: 127

Answers (2)

Vrushali Pawar
Vrushali Pawar

Reputation: 3803

You should write it as;

def index
  @display = Varient.joins(:product).where(is_active: true).order(:price).select('products.id as id, products.title, products.description, price, quantity, variants.id as variant_id')
end

Upvotes: 0

Frederick Cheung
Frederick Cheung

Reputation: 84132

Your code isn't using the eager loaded data which is why adding includes is slowing things down - it's just extra work.

In general if you call query methods ( where, order, etc) rails can't use the eager loaded data. Instead you can make a new association:

has_many :active_variants,  -> { where(is_active: true).order(:price) }, class_name: "Variant"

Then eager load and use this association instead of the variants association.

Upvotes: 1

Related Questions