我在使用update_all
. 为了解释这个问题,我们有 2 个类,Meter
并且Readings
. 每个仪表都有许多读数。仪表具有属性unit
,例如能量单位 kWh、MWh、... 和multiplier
,将读数状态相乘以获得最终值。当用户想要更新Meter
参数(unit
, multiplier
)时,我们Interactors
先更新Readings
状态,然后保存Meter
自己。所有这些操作都发生在一个事务中,所以如果一个失败,那么所有的都会失败。但是我们遇到了这样的情况,当仪表被保存并且读数没有更新时,反之亦然。我检查了,当仪表没有正确保存时,它会导致context.fail!
. Readings
使用update_all
没有任何成功检查,但我读到,update_all
直接进入数据库,当它在约束上失败时,它会因异常而失败。
我没有找到任何方法,如何复制它。
// update readings
class Meters::ChangeUnit
// includes
def call
coefficient = 1.0
coefficient *= unit_change if context.meter.energy_unit_changed?
coefficient *= multiplier_change if context.meter.multiplier_changed?
return if coefficient == 1.0
// this probably fails:
context.meter.readings.update_all "state = state * #{coefficient}"
end
// ...
end
// save meter
class Meters::Save
include Meters::BaseInteractor
def call
context.fail! meter_errors: context.meter.errors unless context.meter.save
end
end
我的想法是使用这样的东西Meters::ChangeUnit call
:
// ...
cnt = context.meter.readings.count
updated = context.meter.readings.update_all "state = state * #{coefficient}"
unless cnt == updated
context.fail! updated_meter_readings: "#{updated}/#{cnt}"
end
// ...
但我不知道如何证明这一点。
编辑1:
// usage in cotroller
context = UpdateMeter.call(meter: @meter, bonds_definition: params[:meters_ids])
// UpdateMeter
class UpdateMeter
include Interactor::Organizer
organize Meters::Update, ProcessAfterCommitQueue
end
// Meters::Update
class Meters::Update
include Interactor::Organizer
include Interactor::InTransaction
organize Meters::ValidateActive,
// ...
Meters::ChangeUnit,
// ...
Meters::Save,
// ...
end
// Interactor::InTransaction
module Interactor::InTransaction
extend ActiveSupport::Concern
included do
around do |interactor|
ActiveRecord::Base.transaction { interactor.call }
end
end
end