object_transactions plugin w/2.x disables AR session store

All,

Win XP Rails 2.0.2 object_transactions plugin (http://code.bitsweat.net/svn/object_transactions/) transaction-simple gem 1.4 (required by object_transactions plugin) AR SQL Server Adapter 1.0 SQL Server 2000

Using the object_transactions plugin with Rails 2.0.2 (and I assume based on what I'm seeing that this goes for Rails 2.x) disables the ability to save to an ActiveRecord based session store (e.g. the sessions table).

I haven't verified this in SQLite or MySQL, but am suspecting that the behavior would be the same.

What appears to happen is that the AR::save call is not ever made under this configuration (see the CGI::Session::ActiveRecordStore::Session.update method in action_controller/session/active_record_store.rb - the call to ActiveRecord::Base.save is never made from here).

Not sure what's happening yet, but I am sure that if I remove the object_transactions plugin from my app., that my AR-based sessions will start saving again.

Wes

SOLUTION:

It appears that this method (lines 52-56 of object_transactions.rb):

# Wrap the original transation instance method with one that takes     # *objects args.     def transaction_with_object_transactions(*objects, &block)       self.class.transaction(*objects, &block)     end

is attempting to call the transaction_with_object_transactions method and pass it a block. But the transaction_with_object_transactions method didn't take a block as a parameter and so could not ultimately pass that block to the "real" transaction method in ActiveRecord.

If you simply add the block into the parameter list for transaction_with_object_transactions and then pass the block on to transaction_without_object_transactions, then it seems to work fine.

What I don't understand is why an exception isn't thrown when the call is made in the first place. I just tested it in irb, is the &block parameter in a Ruby method call always optional?

Here's a patch - Austin Ziegler - if you're out there, am I right?

$ diff -u orig_object_transactions.rb object_transactions.rb --- orig_object_transactions.rb 2008-02-28 14:24:47.010000000 -0600 +++ object_transactions.rb 2008-03-19 19:11:47.055985400 -0500 @@ -59,11 +59,11 @@        # Wrap the original transaction class method with one that manages        # an object-level transaction in addition to the database transaction.        # If an exception is caught, the object's state is rolled back. - def transaction_with_object_transactions(*objects) + def transaction_with_object_transactions(*objects, &block)          objects.each { |o| o.extend Transaction::Simple }          objects.each &:start_transaction

- transaction_without_object_transactions + transaction_without_object_transactions(&block)

         objects.each &:commit_transaction        rescue Exception => object_transaction_rollback

One last thing.

I assert that the object_transactions plugin, in it's current state, not only doesn't allow for sessions to be saved - it doesn't allow for anything to be saved to the database, since the calls that were not being made were basically the AR::Base save calls. This implies that no data could be persisted to the database.

Wes

Wes Gamble wrote:

$ diff -u orig_object_transactions.rb object_transactions.rb --- orig_object_transactions.rb 2008-02-28 14:24:47.010000000 -0600 +++ object_transactions.rb 2008-03-19 19:11:47.055985400 -0500 @@ -59,11 +59,11 @@        # Wrap the original transaction class method with one that manages        # an object-level transaction in addition to the database transaction.        # If an exception is caught, the object's state is rolled back. - def transaction_with_object_transactions(*objects) + def transaction_with_object_transactions(*objects, &block)          objects.each { |o| o.extend Transaction::Simple }          objects.each &:start_transaction

- transaction_without_object_transactions + transaction_without_object_transactions(&block)

         objects.each &:commit_transaction        rescue Exception => object_transaction_rollback

Updated Diff (Jeremy Kemper - where are you?)

It turns out that the block needs to be passed only if present - duh.

$ diff -u orig_object_transactions.rb object_transactions.rb --- orig_object_transactions.rb 2008-02-28 14:24:47.010000000 -0600 +++ object_transactions.rb 2008-03-27 16:50:39.796592000 -0500 @@ -59,11 +59,11 @@        # Wrap the original transaction class method with one that manages        # an object-level transaction in addition to the database transaction.        # If an exception is caught, the object's state is rolled back. - def transaction_with_object_transactions(*objects) + def transaction_with_object_transactions(*objects, &block)          objects.each { |o| o.extend Transaction::Simple }          objects.each &:start_transaction

- transaction_without_object_transactions + block ? transaction_without_object_transactions(&block) : transaction_w ithout_object_transactions

         objects.each &:commit_transaction        rescue Exception => object_transaction_rollback

I don't believe that the previous post is a necessary patch.

Here is a copy of an email that I sent to Jeremy Kemper about this plugin. At the end of the day, I cannot get my objects to save, so I give up. I'm going to stop using object-level transactions, and remove this plugin from my project.

Perhaps this email will help someone who runs into the same issue.

Wes