ruby-on-rails

controller action iterates, thereby generating an N+1 condition


A controller action that creates multiple objects within a loop is a candidate for N+1 queries. Yet, the the following segment

shop_id = section.shop_id
section_id = section.id
serving_table_id = section.serving_table.id
range = 1..i
range.each do |i|
  @cover = Cover.create(shop_id: shop_id, section_id: section_id, serving_table_id: serving_table_id, name: i )      
end

event though the attributes to be saved are defined before the iteration block,
is generating via prosopite gem an N+1 query detection,
for each of the shop, parti and serving_table objects.

Not being a query for a collection, includes would be inapplicable.

How does one avoid N+1 queries in this instance?


Solution

  • The ActiveRecord::Base#insert_all (https://apidock.com/rails/v7.1.3.4/ActiveRecord/Persistence/ClassMethods/insert_all) can take an array of hashes to create

    shop_id = section.shop_id
    section_id = section.id
    serving_table_id = section.serving_table.id
    range = 1..i
    
    Cover.insert_all(
      range.map do |i|
        { shop_id: shop_id, section_id: section_id, serving_table_id: serving_table_id, name: i }
      end
    )
    

    Be careful of statement rollback in case one is invalid.