如果其中一个数据库更新失败,则rails db transaction不会回滚

时间:2014-04-04 18:37:32

标签: ruby-on-rails ruby postgresql transactions rails-activerecord

我的模型中有以下方法:

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来更改任务的状态。它应该仍然会回滚。我的交易有什么问题

1 个答案:

答案 0 :(得分:1)

你误解了什么是“失败”;记录验证不是“失败”,它们是使用您的应用程序的正常部分,并且它们不会强制进行任何类型的数据库回滚。

您需要显式取消事务,或者通过异常保留事务块,以使事务失败。目前,您已成功到达事务的末尾,因此一切都很乐意提交到数据库。

正如已经建议的那样,最佳解决方案是update_attributes!通过抛出异常使您的验证成为真正的失败。关于update_attributes! ...

的问题
  

尝试了它并且它确实进行了回滚,但它也阻止程序运行并且错误消息不显示

这就是重点。如果update_attributes!失败,则没有理由继续执行其余代码,因为所有操作都是创建/更新新记录。事务的重点是无论如何都要回滚这些更改,因此异常是通过阻止代码运行来完美地完成其工作。

如果未显示验证错误,则应处理异常并正常呈现以防止Rails在异常离开您的方法时呈现错误页面。