Search code examples
mysqlruby-on-railsrubyactiverecordtransactions

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.


Solution

  • 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