保存前计算嵌套项目

时间:2019-11-03 13:43:29

标签: ruby-on-rails nested cocoon-gem

让我们拥有订单和商品模型。

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。 创建订单时如何获取要使用该商品的商品数量?

2 个答案:

答案 0 :(得分:1)

您要查找的是“计数器缓存”。它完全实现了您要执行的操作。 ActiveRecord可以为您做到这一点:

belongs_to :post, :counter_cache => true

有两个宝石可以做到这一点,每当创建或删除子记录时,都会更新父记录中的计数字段。

宝石counter-cache简单地完成了工作。另一个counter-culture则更进一步,包括支持计算has_many :through关系中的子项。

您的示例更加有趣,因为您不是在寻找计数,而是计算计数。因此,您可以随便滚动,然后使用它来动态计算packed_volume,可能是在模型上的一种方法中,该方法与您的compute_packed_volume()方法非常相似。

如果您想将实际的卷存储在父记录中(可能计算起来非常昂贵),则需要从在父模型上放置回调到在子模型上放置回调。 counter_culture宝石通过其“ 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的Item添加回调,以增加/减少父记录。如果您的体积计算变得更加复杂,那么在更改记录时,您可能还需要更新顺序。

答案 1 :(得分:0)

尝试使用size,它将不会运行查询

items.size * 0.1O

希望有帮助!