使用ActiveRecord,有没有办法在after_update期间获取记录的旧值
-
03-07-2019 - |
题
使用一个简单示例进行设置:我有一个表( Totals
),其中包含每条记录的 amount
列的总和在第二个表中( Things
)。
当 thing.amount
更新时,我想简单地将旧值和新值之间的差异添加到 total.sum
。
现在我在 before_update
期间减去 self.amount
,并在 after_update
期间添加 self.amount
。这使得WAY过于信任更新成功。
约束:我不想简单地重新计算所有交易的总和。
问题:很简单,我想在 after_update
回调期间访问原始值。你有什么方法可以做到这一点?
更新:我将采用Luke Francl的想法。在 after_update
回调期间,您仍然可以访问 self.attr_was
值,这正是我想要的。我还决定使用 after_update
实现,因为我想在模型中保留这种逻辑。这样,无论我将来如何决定更新交易,我都知道我正在更新交易总和。感谢大家的实施建议。
解决方案
同意每个人对交易的看法。
那说......
从Rails 2.1开始,ActiveRecord会跟踪对象的属性值。因此,如果您有一个 total
属性,您将拥有 total_changed?
方法和一个返回旧值的 total_was
方法。
无需在模型中添加任何内容即可跟踪此情况。
更新:以下是 ActiveModel :: Dirty的文档按要求。
其他提示
其他一些人提到在交易中包装所有这些,但我认为这是为你完成的; 您只需要通过在after_ *回调中引发错误异常来触发回滚。
请参阅 http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
save,save!或destroy调用的整个回调链在事务中运行。这包括after_ * hooks。如果一切顺利,一旦链完成就会执行COMMIT。
如果before_ *回调取消了该动作,则发出ROLLBACK。您还可以在任何回调中触发ROLLBACK引发异常,包括after_ * hooks。但请注意,在这种情况下,客户端需要知道它,因为普通的保存会引发此类异常,而不是静默地返回false。
分别使用旧值和新值获取所有已更改的字段:
person = Person.create!(:name => 'Bill')
person.name = 'Bob'
person.save
person.changes # => {"name" => ["Bill", "Bob"]}
ActiveRecord :: Dirty 是一个内置于ActiveRecord中用于跟踪的模块属性变化。因此,您可以使用 thing.amount_was
来获取旧值。
将此添加到您的模型中:
def amount=(new_value)
@old_amount = read_attribute(:amount)
write_attribute(:amount,new_value)
end
然后在after_update代码中使用@old_amount。
首先,您应该在事务中执行此操作以确保您的数据一起写入。
要回答您的问题,您可以将成员变量设置为before_update中的旧值,然后您可以在after_update中访问该值,但这不是一个非常优雅的解决方案。
创意1:将更新包装在数据库事务中,这样如果更新失败,则Totals表不会更改: ActiveRecord Transactions docs
创意2:在before_update期间将旧值存储在@old_total中。