Ruby-on-rails 使用 ActiveRecord,有没有办法在 after_update 期间获取记录的旧值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/607069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using ActiveRecord, is there a way to get the old values of a record during after_update
提问by Abel
Setup using a simple example:I've got 1 table (Totals) that holds the sum of the amountcolumn of each record in a second table (Things).
使用一个简单示例进行设置:我有 1 个表 ( Totals),其中包含amount第二个表 ( Things)中每条记录的列的总和。
When a thing.amountgets updated, I'd like to simply add the difference between the old value and the new value to total.sum.
当 athing.amount更新时,我想简单地将旧值和新值之间的差异添加到total.sum.
Right now I'm subtracting self.amountduring before_updateand adding self.amountduring after_update. This places WAY too much trust in the update succeeding.
现在我正在减去self.amountduringbefore_update并添加self.amountduring after_update。这对更新成功给予了太多的信任。
Constraint:I don't want to simply recalculate the sum of all the transactions.
约束:我不想简单地重新计算所有交易的总和。
Question:Quite simply, I'd like to access the original value during an after_updatecallback. What ways have you come up with do this?
问题:很简单,我想在after_update回调期间访问原始值。你想出了什么方法来做到这一点?
Update:I'm going with Luke Francl's idea. During an after_updatecallback you still have access to the self.attr_wasvalues which is exactly what I wanted. I also decided to go with an after_updateimplementation because I want to keep this kind of logic in the model. This way, no matter how I decide to update transactions in the future, I'll know that I'm updating the sum of the transactions correctly. Thanks to everyone for your implementation suggestions.
更新:我同意 Luke Francl 的想法。在after_update回调期间,您仍然可以访问self.attr_was我想要的值。我还决定采用一个after_update实现,因为我想在模型中保留这种逻辑。这样,无论我将来如何决定更新事务,我都会知道我正在正确更新事务的总和。感谢大家的实施建议。
回答by Luke Francl
Ditto what everyone is saying about transactions.
同上每个人对交易的看法。
That said...
那说...
ActiveRecord as of Rails 2.1 keeps track of the attribute values of an object. So if you have an attribute total, you will have a total_changed?method and a total_wasmethod that returns the old value.
从 Rails 2.1 开始,ActiveRecord 会跟踪对象的属性值。因此,如果您有一个属性total,您将拥有一个total_changed?方法和一个total_was返回旧值的方法。
There's no need to add anything to your model to keep track of this anymore.
无需再向您的模型添加任何内容来跟踪此情况。
Update:Here is the documentation for ActiveModel::Dirtyas requested.
更新:这是按要求提供的ActiveModel::Dirty文档。
回答by Manish Shrivastava
Appending "_was" to your attribute will give you the previous value before saving the data.
将“_was”附加到您的属性将在保存数据之前为您提供先前的值。
These methods are called dirty methodsmethods.
这些方法称为脏方法。
Cheers!
干杯!
回答by Gabe Hollombe
Some other folks are mentioning wrapping all this in a transaction, but I think that's done for you; you just need to trigger the rollback by raising an exception for errors in the after_* callbacks.
其他一些人提到将所有这些都包装在一个事务中,但我认为这对你来说已经完成了;您只需要通过为 after_* 回调中的错误引发异常来触发回滚。
See http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
见http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
The entire callback chain of a save, save!, or destroy call runs within a transaction. That includes after_* hooks. If everything goes fine a COMMIT is executed once the chain has been completed.
If a before_* callback cancels the action a ROLLBACK is issued. You can also trigger a ROLLBACK raising an exception in any of the callbacks, including after_* hooks. Note, however, that in that case the client needs to be aware of it because an ordinary save will raise such exception instead of quietly returning false.
save、save! 或 destroy 调用的整个回调链在事务中运行。这包括 after_* 钩子。如果一切顺利,一旦链完成,就会执行 COMMIT。
如果 before_* 回调取消操作,则发出 ROLLBACK。您还可以触发 ROLLBACK 在任何回调中引发异常,包括 after_* 钩子。但是请注意,在这种情况下,客户端需要意识到这一点,因为普通的保存会引发此类异常,而不是悄悄地返回 false。
回答by thomax
To get all changed fields, with their old and new values respectively:
要获取所有更改的字段,分别使用它们的旧值和新值:
person = Person.create!(:name => 'Bill')
person.name = 'Bob'
person.save
person.changes # => {"name" => ["Bill", "Bob"]}
回答by John Topley
ActiveRecord::Dirtyis a module that's built into ActiveRecord for tracking attribute changes. So you can use thing.amount_wasto get the old value.
ActiveRecord::Dirty是一个内置于 ActiveRecord 的模块,用于跟踪属性更改。所以你可以使用thing.amount_was来获取旧值。
回答by Daniel Von Fange
Add this to your model:
将此添加到您的模型中:
def amount=(new_value)
@old_amount = read_attribute(:amount)
write_attribute(:amount,new_value)
end
Then use @old_amount in your after_update code.
然后在您的 after_update 代码中使用 @old_amount。
回答by jonnii
Firstly, you should be doing this in a transaction to ensure that your data gets written together.
首先,您应该在事务中执行此操作以确保您的数据被写入在一起。
To answer your question, you could just set a member variable to the old value in the before_update, which you can then access in the after_update, however this isn't a very elegant solution.
要回答您的问题,您可以将一个成员变量设置为 before_update 中的旧值,然后您可以在 after_update 中访问它,但这不是一个非常优雅的解决方案。
回答by bradheintz
Idea 1: Wrap the update in a database transaction, so that if the update fails your Totals table isn't changed: ActiveRecord Transactions docs
想法 1:将更新包装在数据库事务中,以便如果更新失败,您的 Totals 表不会更改:ActiveRecord Transactions docs
Idea 2: Stash the old value in @old_total during the before_update.
想法 2:在 before_update 期间将旧值存储在 @old_total 中。

