Rails 7.1 Active Record Transaction on return, break and throw

In the latest Rails, a significant change has been made to the behaviour of transactions. Specifically, using return, break, or throw statements will no longer trigger an automatic rollback of the transaction.

In Rails 6.1 use of return, break, and throw statements within transactions has been deprecated.

For example in the below code

class User < ApplicationRecord
  def self.transaction_with_return
    User.transaction do
      User.create(email: "test@example.com",name: "Test")
      return
      User.create(email: "test1@example.com",name: "Test1")
    end
    puts User.count
  end
end

If we run the method User.transaction_with_return, only 1 user is created as the transaction is exited with the return keyword and the same outcome occurs whether we use the break or throw keyword.

The rationale behind this deprecation was closely tied to the behaviour of the timeout library in Ruby 2.3.

In Ruby 2.3, the timeout library utilized the throw mechanism to exit a transaction silently if no second argument (specifically, an Exceptional Class) was provided.

However, with the release of timeout version 0.4.0, it reverted to raising exceptions in such cases.

With this change, ActiveRecord has reinstated its previous behaviour prior to version 6.1, where transactions will be committed even if return, break, or throw statements are used.

But now in Rails 7.1 transactions will not exit with the return, break or throw keyword. This was the original behaviour of Rails before version 6.1

Let's take the example again

class User < ApplicationRecord
  def self.transaction_with_return
    User.transaction do
      User.create(email: "test@example.com",name: "Test")
      return
      User.create(email: "test1@example.com",name: "Test1")
    end
    puts User.count
  end
end

So now User.transaction_with_return, will create two users instead of one.

This is the default behaviour in Rails 7.1 but if you want it version between 7.1 and 6.1 you can get by

Rails.application.config.active_record.commit_transaction_on_non_local_return = true

Related Links

Did you find this article valuable?

Support Rashmi Yadav by becoming a sponsor. Any amount is appreciated!