我有一个模型PositionGroup
那个has_many :positions
。
[无论何时添加或保存位置,我都希望它更新PositionGroup
上的属性。例如。当新位置已添加到PositionGroup
时,我想将position.volume
添加到现有position_group.total_units
中。
因此,请考虑以下示例:
pg.total_units = 100
position2.volume = 50
# then pg.total_units should be updated to:
pg.total_units = 150
我知道我可以通过关联回调来做到这一点,这很好。
问题是,当我想更新前一个头寸的交易量时会发生什么。如果添加before_save
或after_save
,则在触发after_add
回调后也会触发该回调-从而人为抬高pg.total_units
数字。
我该如何解决?
我想出了一个解决方案。
[基本上,而不是使用许多after_save, before_save & after_add
回调,我只是在一种模型上使用touch: true
而在另一种模型上使用after_touch
。那解决了我所有的问题。
为了更加清楚,我在Position
模型上添加了:
belongs_to :position_group, touch: true
然后在我的PositionGroup
模型上,我添加了:
after_touch :recompute_total_units
private
def recompute_total_units
update_column(:total_units, positions.sum(:volume))
end
Voila。
如果我正确理解了这个问题,这是防止这种人为膨胀的一种天真的方法:
class Position < ApplicationRecord
belongs_to :position_group
before_save :update_position_group_total_units
def update_position_group_total_units
delta = volume - (volume_was || 0)
position_group.update!(total_units: position_group.total_units + delta)
end
end
class PositionGroup < ApplicationRecord
has_many :positions
end
在此处查看文档:https://api.rubyonrails.org/classes/ActiveModel/Dirty.html
警告,如果保存由于某种原因而失败,position_group仍将更新,导致另一种错误的计算。
我最喜欢触摸方法,如您所发现:
class Position < ApplicationRecord
belongs_to :position_group, touch: true
end
class PositionGroup < ApplicationRecord
has_many :positions
after_touch :recompute_total_units
private
def recompute_total_units
update_column(:total_units, positions.sum(:volume))
end
end