保存前计算嵌套项目

Count nested item before save

让订单和项目模型。

class Order < ApplicationRecord
  has_many :items, inverse_of: :order, dependent: :delete_all

  before_save do
    self.packed_volume = compute_packed_volume
  end

  private

  def compute_packed_volume
    items.count * 0.1O
  end
end

class Item < ApplicationRecord
  belongs_to :order, inverse_of: :items
end

问题是 items.count 等于 0,因为尚未创建项目。 我们如何在创建订单时获取将要创建的项目数以使用它?

您要找的是 "counter cache"。它实现了你正在尝试做的事情。 ActiveRecord 可以为您做到这一点:

belongs_to :post, :counter_cache => true

有几个 gem 执行此操作,每当创建或删除 child 记录时更新 parent 记录中的计数字段。

Gem counter-cache 很简单。另一个,counter-culture 更进一步,包括支持在 has_many :through 关系中计算 children。

你的例子有点有趣,因为你不是在寻找计数,而是在计算计数。因此,您可以使用它并使用它来动态计算 packed_volume,可能在模型上的方法与您的 compute_packed_volume() 方法非常相似。

如果您想在 parent 记录中存储实际交易量(也许计算起来非常昂贵),您需要从将回调放在 parent 模型上转变为将它们放在child 模型。 counter_culture gem 支持 "Delta Magnitude"。像这样:

class Item < ActiveRecord::Base
  belongs_to :order
  counter_culture :order, column_name: :packed_volume, delta_magnitude: 0.1
end

class Order < ActiveRecord::Base
  has_many :items
end

delta_magnitude参数可以带proc,所以可以做更复杂的事情。也许是这样的:

counter_culture :order, column_name: :packed_volume, delta_magnitude: -> {|item| item.length * item.width * item.height }

如果您有其他要求无法使用 gem,您可以按照这些思路推出自己的解决方案。您需要为 after_createbefore_destroy 添加回调到 increment/decrement parent 记录。如果您的交易量计算变得更加复杂,您可能还需要在记录更改时更新订单。

尝试 size,它不会 运行 查询

items.size * 0.1O

希望对您有所帮助!