Philip7899
Philip7899

Reputation: 4677

rails db transaction not rolling back if one of the db updates fails

I have the following method in my model:

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

I am new to transactions in rails, but my understanding was that if one of the database interactions failed, the whole transaction would be rolled back. In the code above, the line:

self.update_attributes(task_params)

is failing, so the database update that occurs from self.task_finished on the line before should be rolled back. For some reason, it is not rolled back.

For background information, although i don't think it should make a difference, the "self.task_finished" line uses the state_machine gem to change the state of task. It should still rollback though. What is wrong with my transaction

Upvotes: 1

Views: 1904

Answers (1)

user229044
user229044

Reputation: 239250

You're misunderstanding what constitutes "failure"; record validations aren't "failure", they're a normal part of using your app, and they don't force any kind of database rollback.

You need to either explicitly cancel the transaction, or leave the transaction block via an exception, for the transaction to fail. Currently, you're successfully reaching the end of the transaction, so everything is happily committed to the database.

As suggested already, the best solution is update_attributes! which makes your validations into real failure by throwing an exception. As for your problem with update_attributes!...

tried that and it did do the rollback, but it also stops the program from running and the error messages don't display

That's the point. If your update_attributes! fails, there's no reason to proceed with the rest of your code, as all that does is create/update new records. The point of the transactions is to roll those changes back anyways, so the exception is doing its job perfectly by preventing that code from running.

If your validation errors aren't displaying, you should handle the exception and render normally to prevent Rails from rendering an error page when the exception leaves your method.

Upvotes: 1

Related Questions