How to tell if already within a database transaction in ruby on rails?

ActiveRecord::Base.transaction do
  Foo.new.bar
end
Foo.new.baz

Can I determine programmatically from within the bar() or baz() methods if a transaction is already taking place? Looking for something that might look like ActiveRecord::Base.within_transaction?, that would return true when called from bar() and false when called for baz().

In case it is relevant, I’m using a mysql database with the mysql2 gem, and am ok with a solution that works only for mysql.

Answer

You can use

ActiveRecord::Base.connection.open_transactions

to see if your method is executed in a transaction.

ActiveRecord::Base.connection.open_transactions == 0 implies that your method is not executed in a transaction. Anything greater than 0 would imply that your method is executed in a transaction. For example ActiveRecord::Base.connection.open_transactions > 0

Update:

from rails documentation

all database statements in the nested transaction block become part of the parent transaction

So number of open transaction will be one even if you are in a nested transaction.

This is what i got in my console

ActiveRecord::Base.transaction do
   User.first.update_attribute(:first_name, "something")
   ActiveRecord::Base.transaction do
       User.first.update_attribute(:last_name, "something")
       p ActiveRecord::Base.connection.open_transactions
   end
end


  (0.3ms)  BEGIN
  User Load (0.8ms)  SELECT "users".* FROM "users" LIMIT 1
  (0.8ms)  UPDATE "users" SET "first_name" = 'something', "updated_at" = '2013-11-20 18:33:52.254088' WHERE "users"."id" = 1
  User Load (0.5ms)  SELECT "users".* FROM "users" LIMIT 1
  (0.4ms)  UPDATE "users" SET "last_name" = 'something', "updated_at" = '2013-11-20 18:33:52.266976' WHERE "users"."id" = 1
  1
  (14.2ms)  COMMIT
  => 1 

Leave a Reply

Your email address will not be published. Required fields are marked *