我有一个Invoice模型,与另一个Cart模型有一个has_one关系,
购物车has_many line_items,每个line_item都有一个带有价格属性的商品。
我的方法如下:
class Invoice < ApplicationRecord
has_one :cart, dependent: :destroy
belongs_to :user
def self.total
sum = 0.0
Cart.all.each do |c|
sum += c.total_value
end
sum
end
end
购物车对象上的total_value方法如下所示:
class Cart < ApplicationRecord
def total_value
sum = 0.0
line_items.each { |l| sum += l.product.price.present? ? l.product.price * l.quantity : 0.0 }
sum
end
end
所以我的问题是,有没有更有效的方法来执行相同的计算可能基于SQL查询而不是数组操作? 它会有多高效? 我也知道我的数组操作很差,所以我怎样才能以更红宝石的方式获得相同的结果呢?
答案 0 :(得分:3)
是否有更有效的方法来执行相同的计算 基于SQL查询而不是数组操作?
是。 SQL比Ruby快得多,几乎无法比较:
def self.total
Cart.joins(line_items: :product)
.sum('COALESCE(products.pharmacy_price * line_items.quantity, 0.0)')
end
但我认为您可能需要的是total
个cart
,而不是全部carts
,它将是实例方法,而不是类实例方法:
def total
self.class
.joins(cart: { line_items: :product })
.where(invoices: { id: id })
.sum('COALESCE(products.pharmacy_price * line_items.quantity, 0.0)')
end
因此,使用情况为Invoice.first.total
,而不是Invoice.total
。
关于total_value
方法 - 您可以使用ActiveRecord级别的计算来编写它,而不是Ruby,这可能会更快:
def total_value
self.class
.joins(line_items: :product)
.where(line_items(cart_id: id))
.sum('COALESCE(products.pharmacy_price * line_items.quantity, 0.0)')
end
至于
我也知道我的数组操作很差,所以我怎么能 以更红宝石的方式达到相同的效果?
您可以使用Enumerable#inject
:
def total_value
line_items.inject(0.0) { |sum, l| sum + l.product.pharmacy_price * l.quantity }
end