How do I get save (no exclamation point) semantics in an ActiveRecord transaction?
I have two models: Person
and Address
which I'd like to create in a transaction. That is, I want to try to create the Person
and, if that succeeds, create the related Address
. I would like to use save
semantics (return true
or false
) rather than save!
semantics (raise an ActiveRecord::StatementInvalid
or not).
This doesn't work because the user.save
doesn't trigger a rollback on the transaction:
class Person
def s开发者_运维技巧ave_with_address(address_options = {})
transaction do
self.save
address = Address.build(address_options)
address.person = self
address.save
end
end
end
(Changing the self.save
call to an if self.save
block around the rest doesn't help, because the Person
save still succeeds even when the Address
one fails.)
And this doesn't work because it raises the ActiveRecord::StatementInvalid
exception out of the transaction
block without triggering an ActiveRecord::Rollback
:
class Person
def save_with_address(address_options = {})
transaction do
save!
address = Address.build(address_options)
address.person = self
address.save!
end
end
end
The Rails documentation specifically warns against catching the ActiveRecord::StatementInvalid
inside the transaction
block.
I guess my first question is: why isn't this transaction block... transacting on both saves?
How about this?
class Person
def save_with_address(address_options = {})
tx_error = false
transaction do
begin
self.save!
address = Address.build(address_options)
address.person = self
address.save!
rescue Exception => e
# add relevant error message to self using errors.add_to_base
raise ActiveRecord::Rollback
tx_error = true
end
end
return true unless tx_error
# now roll back the Person TX.
raise ActiveRecord::Rollback
return false
end
end
I don't like the way the TX is implemented. But this is how you can work around the issues.
Tell ActiveRecord to do this for you. Saves you mounds of problems:
class Person < ActiveRecord::Base
belongs_to :address, :autosave => true
end
The nice thing is that Person's errors will contain address' validation errors, correctly formatted.
See the AutosaveAssocation module for more information.
精彩评论