Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 668
user1385729 Avatar asked Nov 20 '13 17:11

user1385729


People also ask

How does ActiveRecord transaction work?

Transactions in ActiveRecordEvery database operation that happens inside that block will be sent to the database as a transaction. If any kind of unhandled error happens inside the block, the transaction will be aborted, and no changes will be made to the DB.

What is database transactions and how it is represented in rails?

Rails transactions are a way to ensure that a set of database operations will only occur if all of them succeed. Otherwise they will rollback to the previous state of data.

What does .save do in Ruby?

The purpose of this distinction is that with save! , you are able to catch errors in your controller using the standard ruby facilities for doing so, while save enables you to do the same using standard if-clauses.


2 Answers

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  
like image 178
usha Avatar answered Sep 18 '22 13:09

usha


In Rails 6.0 you can use:

ActiveRecord::Base.connection.transaction_open? 
like image 21
Eugeniu Torica Avatar answered Sep 18 '22 13:09

Eugeniu Torica