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
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">]