首页 > 解决方案 > 如果触发关联回调,如何防止触发模型回调?

问题描述

我有一个PositionGroup模型has_many :positions

每当添加或保存位置时,我希望它更新PositionGroup. 例如,当一个新的位置被添加到 aPositionGroup时,我想将它添加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

我意识到我可以通过关联回调来做到这一点,这很好。

问题是,当我想更新前一个头寸的交易量时会发生什么。如果我添加 abefore_save或 an after_save,则该回调也将在触发回调后after_add触发 - 从而人为地夸大pg.total_units数字。

我该如何解决这个问题?

标签: ruby-on-railscallbackruby-on-rails-5

解决方案


如果我正确理解了这个问题,这是防止人为通货膨胀的一种天真的方法:

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

推荐阅读