我有一个模型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
的数字
我该如何解决此问题?
我找到了一个解决方案。
基本上,我只是在一个模型上使用touch: true
,在另一个模型中使用after_touch
,而不是使用许多after_save, before_save & after_add
回调。这解决了我所有的问题。
为了更清晰,在我的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
沃伊拉。
如果我正确理解了这个问题,这里有一种防止人为通货膨胀的天真方法:
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