如果触发了关联回调,如何防止触发模型回调



我有一个模型PositionGrouphas_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_saveafter_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

最新更新