我想按库存数量在索引视图中订购一些产品(如果有0,则排在最后;如果大于0,则排在前)。
我有以下型号:产品,变型和库存
产品型号
has_many :stocks, through: :variants
变体模型
belongs_to :product
库存型号
belongs_to :variant
这就是我找到一种产品的全部库存的方式...
p = Product.last
p.stocks.map(&:quantity).sum
现在,如何找到所有产品库存的数量,从最大到最小?
答案 0 :(得分:4)
如果我正确理解,您正在寻找根据Product
数量之和按降序返回的所有Stock
。如果是这样,这应该为您工作。
@products = Product.left_joins(variants: :stocks)
.group(:id)
.select(Product.arel_table[Arel.star],
Stock.arel_table[:quantity].sum.as('total_quantity'))
.order('total_quantity DESC')
这将导致
SELECT
products.*,
SUM(stocks.quantity) AS total_quantity
FROM
products
LEFT OUTER JOIN variants ON variants.product_id = products.id
LEFT OUTER JOIN stocks ON stocks.variant_id = variants.id
GROUP BY
products.id
ORDER BY
total_quantity DESC
似乎是您想要的。这还将向所有已加载的total_quantity
对象添加虚拟属性Product
,您可以将其用于显示目的,而无需再次访问数据库,例如
@products.each do |p|
p.total_quantity # virtual attribute equal to SUM(stocks.quantity)
end
最后一点; ;如果您在代码中实际使用了p.stocks.map(&:quantity).sum
,出于效率考虑,可以将其更改为p.stocks.sum(:quantity)
。这将执行一个适合于SELECT SUM()
返回的ActiveRecord::Relation
的{{1}}查询,这通常比加载所有p.stocks
对象然后生成一个{{1} }的数量,然后将这些数量迭代累加为一个数值。
答案 1 :(得分:0)
如果您只是在视图中执行此操作,而不关心是以ActiveRecord::Relation
还是Array
结尾,则可以使用Enumerable#sort_by方法。
例如在haml视图中:
- @products.sort_by { |p| p.stocks.sum(:quantity) }.reverse.each do |product|
Qty: #{product.stocks.sum(:quantity)}
如果要在Product
上定义一个计算其数量的方法,如下所示:
def stock_quantity
stocks.sum(:quantity)
end
您可以清理一下:
- @products.sort_by(&:stock_quantity).reverse.each do |product|
Qty: #{product.stock_quantity}