Hi everyone!
I have a script running on a client to identify product bundles using tags and apply discounts. Recently, I’ve been getting A LOT of MemoryQuotaExceeded errors. Despite those errors, the script is working normally. Given that I’m not a Ruby expert (to say the least), could I improve the memory usage of this script? Any help is appreciated.
The code is the following:
products_in_cart = Input.cart.line_items
products_with_tag = {}
variants_with_discount = []
# Step 1: Group products by their tags
products_in_cart.each do |line_item|
variant = line_item.variant
product = variant.product
product.tags.each do |tag|
if tag.start_with?('bundle')
key = tag # Use the tag as the key for grouping
products_with_tag[key] ||= []
products_with_tag[key] << {
id: product.id,
variant: variant.id,
quantity: line_item.quantity,
tag: tag
}
break # If one tag matches, move to the next product
end
end
end
unless products_with_tag.empty?
# Step 2: Identify bundles
products_with_tag.each do |_tag, products_in_bundle|
# Create a hash where the keys are the tags and the values are arrays of product IDs
products_by_id = products_in_bundle.group_by { |item| item[:id] }
# Flatten the array of products
flattened_products = products_by_id.values.flatten(1)
# Pair them up
paired_products = []
flattened_products.each_slice(2) { |pair| paired_products << pair }
# If there's an odd number of products, remove the last one
paired_products.pop if paired_products.last.size % 2 != 0
# Now we have all possible pairs of products with the same tag
paired_products.each do |pair|
# Check if both elements of each pair have the same quantity
if pair[0][:quantity] != pair[1][:quantity]
# Identify the product with the largest and smallest quantity
max_product = pair.max_by { |product| product[:quantity] }
min_product = pair.min_by { |product| product[:quantity] }
# Calculate the difference as the result of the largest quantity divided by the smallest quantity
difference = max_product[:quantity] / min_product[:quantity]
# Add a property with that difference to the object with the largest quantity
max_product[:difference] = difference
end
# Create a new object with the variant, quantity, and difference (if any) from each pair
new_object = pair.map { |product| { variant: product[:variant], quantity: product[:quantity], difference: product[:difference] } }
# Add the new object to the array of all new objects
variants_with_discount << new_object
end
end
# Step 3: Add discounts
products_in_cart.each do |line_item|
variant = line_item.variant
# Find the corresponding new object for this variant
var = variants_with_discount.flatten.find { |obj| obj[:variant] == variant.id }
# If a new object was found and it has a difference, adjust the discount
if var && var[:difference]
calc = 0.25 / var[:difference]
discount = 1 - calc
message = 'Bundle'
line_item.change_line_price(line_item.line_price * discount, message: message)
elsif var
discount = 0.75
message = 'Bundle'
line_item.change_line_price(line_item.line_price * discount, message: message)
end
end
end
Output.cart = Input.cart