This project is archived and is in readonly mode.

#1951 ✓resolved
Ken Collins

ActiveRecord::Rollback Does Not Work In Nested Transactions

Reported by Ken Collins | February 12th, 2009 @ 02:29 PM | in 2.x

While I was working on the latest SQL Server adapter for rails 2.3 I noticed this in the docs and that it does not work at all in all DBs/core.


   # == Nested transactions
    #
    # #transaction calls can be nested. By default, this makes all database
    # statements in the nested transaction block become part of the parent
    # transaction. For example:
    #
    #   User.transaction do
    #     User.create(:username => 'Kotori')
    #     User.transaction do
    #       User.create(:username => 'Nemu')
    #       raise ActiveRecord::Rollback
    #     end
    #   end
    #   
    #   User.find(:all)  # => empty

I can totally see the issue but can not think of a good way to fix #transaction to let one block let another know this was set and hence all the block that finally answers true to transaction_open to do the work. I would love for some feedback for a way I might be able to patch this and/or if the docs should be changed to say that that exception class can only be used in the first transaction block.

BTW, there is a test in transaction_test.rb called #test_manually_rolling_back_a_transaction that I had copied but could never make it pass.


  def test_manually_rolling_back_a_nested_transaction
    Topic.transaction do
      @first.approved  = true
      @first.save
      Topic.transaction do
        @second.approved = false
        @second.save
        raise ActiveRecord::Rollback
      end
    end
    assert !Topic.find(1).approved?, "First shouldn't have been approved"
    assert Topic.find(2).approved?, "Second should still be approved"
  end

I believe Michael added this exception class, so I assigned him the ticket?

Comments and changes to this ticket

  • Michael Koziarski

    Michael Koziarski February 13th, 2009 @ 08:53 AM

    Yeah, that's not possible, and can't be possible so the docs need updating.

    If you raise another exception it'll rollback, but obviously AR::Rollback doesn't, and shouldn't, propagate.

  • Michael Koziarski

    Michael Koziarski February 13th, 2009 @ 08:54 AM

    • Assigned user changed from “Michael Koziarski” to “Pratik”

    Needs fixing in docrails

  • Ken Collins

    Ken Collins February 13th, 2009 @ 02:19 PM

    Agreed, it was looking very hackish in my code attempts to implement this. And indeed the raising of some other exception does do the job.

    I'll add the doc changes to support this and submit a patch soon.

  • Pratik

    Pratik February 13th, 2009 @ 02:23 PM

    Hey Ken,

    Just lemme know your github username and I'll give you commit access to docrails.

  • Ken Collins

    Ken Collins February 13th, 2009 @ 02:25 PM

    Ah duh, I think I might already be on, it's "metaskills".

  • Pratik

    Pratik February 13th, 2009 @ 02:33 PM

    Yup, you're already there :)

  • CancelProfileIsBroken

    CancelProfileIsBroken April 22nd, 2009 @ 10:29 PM

    • State changed from “new” to “resolved”

    Fixed in docrails

  • Ken Collins

    Ken Collins April 23rd, 2009 @ 12:38 AM

    Thanks to whomever got that in docrails, I've been a bit too busy lately.

  • Jason Yuen

    Jason Yuen January 8th, 2010 @ 11:28 PM

    • Tag changed from 2.3, activerecord, nested, rollback, transaction to 2, activerecord, nested, rollback, transaction

    @Michael: I was wondering about your comment that "obviously AR::Rollback doesn't, and shouldn't, propagate." We are nesting our calls to #transaction without using :require_new. In this situation, we are observing that when we raise ActiveRecord::Rollback in our inner transaction block, the database transaction does not get rolled back.

    User.transaction do
      User.create(:username => 'Kotori')
      User.transaction do
        User.create(:username => 'Nemu')
        raise ActiveRecord::Rollback
      end
    end
    

    In this example, neither 'Kotori' nor 'Nemu' should exist in the database but they do. It seems like this is a bug so I've attached a patch (for 2.3.4 but it doesn't seem like the code has changed in master) which addresses this issue (unless of course, there is a reason why this isn't actually an issue). Basically, the rollback exception is always re-raised until we get to the outermost transaction block.

  • Jason Yuen

    Jason Yuen January 8th, 2010 @ 11:29 PM

    • Tag changed from 2, activerecord, nested, rollback, transaction to 2.3, activerecord, nested, rollback, transaction
  • Jason Yuen

    Jason Yuen January 14th, 2010 @ 06:36 PM

    • Tag changed from 2.3, activerecord, nested, rollback, transaction to 2, activerecord, nested, rollback, transaction

    Sorry guys - I think I was a little overzealous with the patch and I hadn't fully thought through all the implications (e.g. how it affects the validation lifecycle). I have an operation in a nested transaction block that causes an ActiveRecord::StaleObjectError. Instead of letting the stale object error propagate, I was rescuing it and re-raising an ActiveRecord::Rollback, thinking that the rollback would propagate across transaction boundaries and rollback operations in outer transaction blocks. I guess I was just being lazy, hoping that I wouldn't have to explicitly handle the stale object error :)

    Sorry again for the noise!

    Jason

  • Jason Yuen

    Jason Yuen January 14th, 2010 @ 06:37 PM

    • Tag changed from 2, activerecord, nested, rollback, transaction to 2.3.x, activerecord, nested, rollback, transaction
  • Ryan Bigg

    Ryan Bigg October 9th, 2010 @ 09:56 PM

    • Tag cleared.
    • Importance changed from “” to “Low”

    Automatic cleanup of spam.

  • Ivan Evtuhovich

    Ivan Evtuhovich December 8th, 2010 @ 09:11 PM

    You fix this only in docrails, but rdoc documentation is wrong (patch attached)

    And i wonder why by default nested transaction rollback do not works?

  • bingbing

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages