Search code examples
ruby-on-railsactiverecordtransactionsrollbackbefore-filter

How do you prevent database changes inside a Rails ActiveRecord before_create filter from getting rolled back when it returns false?


I've added a before_create filter to one of my Rails ActiveRecord models and inside that filter I'm doing some database updates.

Sometimes I return false from the filter to prevent the creation of the target model, but that is causing all the other database changes I made (while inside the filter) to get rolled back.

How can I prevent that?

Update #1: Here's some pseudo code explaining my problem:

class Widget < ActiveRecord::Base
  before_create :update_instead

  def update_instead
    if some_condition?
      update_some_record_in_same_model # this is getting rolled back
      return false # don't create a new record
    else
      return true # let it continue
    end
  end
end

Update #2: Some good answers below but each had its shortcomings. I ended up overridding the create method like so:

def create
  super unless update_instead? # yes I reversed the return values from above
end

Solution

  • I just had to do this recently. You need to specifically request another connection from AR. Then execute your changes on that connection. This way, if the creation fails and rolls back the transaction, your callback's changes were already committed in a different transaction.

    Ignore my answer above. The example code you just gave really clarified things.

    class Foo < ActiveRecord::Base
      before_create :update_instead
    
      def update_instead
        dbconn = self.class.connection_pool.checkout
        dbconn.transaction do
          dbconn.execute("update foos set name = 'updated'")
        end
        self.class.connection_pool.checkin(dbconn)
        false
      end
    end
    
    
    >> Foo.create(:name => 'sam')
    => #<Foo id: nil, name: "sam", created_at: nil, updated_at: nil>
    >> Foo.all
    => [#<Foo id: 2, name: "updated", created_at: "2009-10-21 15:12:55", updated_at: "2009-10-21 15:12:55">]