Rails Transactions

Hi!
I am confused about Rails transactions… Look at the following
code:

CODE BEGINS

def save_instances(entity_id, instance_resources)
# This contains the instance ids of the newly created instances
instance_ids = []

Instance.transaction do
  instance_resources.each do |instance_resource|
    instance_ids << save_instance(entity_id, instance_resource)
  end
end



return instance_ids

end
CODE ENDS

Now the save_instance method is like this:

def save_instance(entity_id, instance_resource)

  instance = Instance.new(:entity_id => entity_id).save!

  detail_ids = get_detail_ids(entity_id)

  instance_resource.each do |detail_name, values|
    save_all_values(instance.id, detail_ids[detail_name], values)
  end
return instance.id

end

And similarly, there is save_all_values method which does a bit more
work. But support for transactions is not working at all. i.e. if an
exception is raised by the methods beneath, the records created
earlier are not rolledback.

I am only starting a single transaction block in the first method so
what’s wrong with all this?
BTW, I am using PostgreSQL 8.2 as backend.

On Apr 10, 6:42 pm, MohsinHijazee [email protected] wrote:

==========
save_all_values(instance.id, detail_ids[detail_name], values)
I am only starting a single transaction block in the first method so
what’s wrong with all this?
BTW, I am using PostgreSQL 8.2 as backend.

Note that this is happening in tests. I mean tests are getting failed.

On 10 Apr 2008, at 14:48, MohsinHijazee wrote:

I am only starting a single transaction block in the first method so
what’s wrong with all this?
BTW, I am using PostgreSQL 8.2 as backend.

Note that this is happening in tests. I mean tests are getting failed.

Tests are special. Because each test itself is wrapped in a
transaction by default and because rails does not support nested
transactions you cannot test your handling of transactions. If you
want to do that you need to turn off transactional fixtures.

Fred

How do I do that?

On Apr 10, 6:50 pm, Frederick C. [email protected]

On 11 Apr 2008, at 12:36, MohsinHijazee wrote:

How do I do that?

set self.use_transactional_fixtures = false (either in your
test_helper.rb which will do it for all tests or just in one of of
your test files)

Fred

Frederick C. wrote:

On 11 Apr 2008, at 12:36, MohsinHijazee wrote:

How do I do that?

set self.use_transactional_fixtures = false (either in your
test_helper.rb which will do it for all tests or just in one of of
your test files)

Fred

OMG,

you do not understand how that just fixed my life. Seriously! I’ve been
bummed out all week cuz my functionals that dealt with transactions were
not working properly. I was trying to assert counts after my controllers
would throw an exception in a transaction and they never matched up.
Even though I searched and read bug filings on a bunch of AR stuff in
the Rails Trac server, I still couldn’t figure out what was going
wrong because I didn’t remember having this prob on my previous Rails
projects.

So to recap and spell it out in case someone else stumbles upon this and
doesn’t yet get it:

  1. Your controllers have something like

def create

assign your params to person, address, credit card

don’t get caught up on the model details as the below

probably isn’t the best object graph

And I know, this is straight outta the agile rails book pp. 492-493

Account.transaction do
@credit_card.address=@address
@account.address=@address

@address.save!
@credit_card.save!
@account.save!
end

flash[:message]=‘Update successful.’
render :action=>‘show’

rescue Exception => ex

@account.valid?
@credit_card.valid?
@address.valid?
render :action=>‘new’

end

  1. Your tests have something like

def test_add_credit_card
count = CreditCard.count

do your post, rollback should happen in logs

assert_not_nil assigns(:credit_card)
assert_equal count, CreditCard.count

end

This totally made my week. Thank you!! :slight_smile: