我的模型中有以下方法:
class Task < ActiveRecord::Base
def update_completed_task(task_params, completed_material_params)
puts 'in update_completed_task method'
transaction do
begin
puts 'inside transaction'
self.task_finished
puts 'after task finished'
self.update_attributes!(task_params)
puts 'after update_attributes'
if completed_material_params
completed_material_params.each do |key, value|
@completed_material = CompletedMaterial.where("identity = ?", value).first
@completed_material.task = self
@completed_material.save
end
end
puts 'affter loop'
UserNotification.freelancer_has_submitted_documents(self.schedule.project, self)
puts 'after user notification change'
rescue
puts 'in rescue again yolo gandi rollback'
end
end
end
end
我对rails中的事务不熟悉,但我的理解是,如果其中一个数据库交互失败,整个事务将被回滚。在上面的代码中,行:
self.update_attributes(task_params)
失败,因此应该回滚之前就行的self.task_finished发生的数据库更新。由于某种原因,它没有回滚。
对于背景信息,虽然我认为它不应该有所作为,但是&#34; self.task_finished&#34; line使用state_machine gem来更改任务的状态。它应该仍然会回滚。我的交易有什么问题
答案 0 :(得分:1)
你误解了什么是“失败”;记录验证不是“失败”,它们是使用您的应用程序的正常部分,并且它们不会强制进行任何类型的数据库回滚。
您需要显式取消事务,或者通过异常保留事务块,以使事务失败。目前,您已成功到达事务的末尾,因此一切都很乐意提交到数据库。
正如已经建议的那样,最佳解决方案是update_attributes!
,通过抛出异常使您的验证成为真正的失败。关于update_attributes!
...
尝试了它并且它确实进行了回滚,但它也阻止程序运行并且错误消息不显示
这就是重点。如果update_attributes!
失败,则没有理由继续执行其余代码,因为所有操作都是创建/更新新记录。事务的重点是无论如何都要回滚这些更改,因此异常是通过阻止代码运行来完美地完成其工作。
如果未显示验证错误,则应处理异常并正常呈现以防止Rails在异常离开您的方法时呈现错误页面。