有没有更好的方法来计算此发票模型的总价值?

时间:2017-04-12 02:55:14

标签: sql ruby-on-rails ruby ruby-on-rails-4 activerecord

我有一个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查询而不是数组操作? 它会有多高效? 我也知道我的数组操作很差,所以我怎样才能以更红宝石的方式获得相同的结果呢?

1 个答案:

答案 0 :(得分:3)

  

是否有更有效的方法来执行相同的计算   基于SQL查询而不是数组操作?

是。 SQL比Ruby快得多,几乎无法比较:

  def self.total
    Cart.joins(line_items: :product)
        .sum('COALESCE(products.pharmacy_price * line_items.quantity, 0.0)')
  end

但我认为您可能需要的是totalcart,而不是全部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