使用一个简单示例进行设置:我有一个表( 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。

追加“_was”在保存数据之前,您的属性将为您提供之前的值。

这些方法称为脏方法方法。

干杯!

分别使用旧值和新值获取所有已更改的字段:

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中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top