Database Transactions


#1

ActiveRecord’s standard procedure for transactions is to send a block,
and throw an exception to roll it back (
http://api.rubyonrails.com/classes/ActiveRecord/Transactions/ClassMethods.html
). I found this rather uncomfortable. I’d like to be able to begin
transactions, commit them, or roll them back from within (fairly)
complex control structures - and having to do everything within a
block, with one way out, is no good.

Any suggestions?

PS This question concerns ActiveRecord, an O/R mapper which can be used
for lots of things. It’s not a rails questions (what’s rails???)


#2

listrecv wrote:

ActiveRecord’s standard procedure for transactions is to send a block,
and throw an exception to roll it back (
http://api.rubyonrails.com/classes/ActiveRecord/Transactions/ClassMethods.html
). I found this rather uncomfortable. I’d like to be able to begin
transactions, commit them, or roll them back from within (fairly)
complex control structures - and having to do everything within a
block, with one way out, is no good.

You can start/commit/rollback transactions manually
(ActiveRecord::Base.connection.start_transaction, IIRC). Though I don’t
see why using a block should be a problem for your control structure.


#3

Andreas S. wrote:

listrecv wrote:

ActiveRecord’s standard procedure for transactions is to send a
block, and throw an exception to roll it back (

http://api.rubyonrails.com/classes/ActiveRecord/Transactions/ClassMethods.html

). I found this rather uncomfortable. I’d like to be able to begin
transactions, commit them, or roll them back from within (fairly)
complex control structures - and having to do everything within a
block, with one way out, is no good.

You can start/commit/rollback transactions manually
(ActiveRecord::Base.connection.start_transaction, IIRC). Though I
don’t see why using a block should be a problem for your control
structure.

+1

Using the block is definitely superior and less error prone. Hint: you
can call methods from the block. :slight_smile:

Kind regards

robert

#4

Okay, I’ll trust you guys know better than I do.
How do I do this with a block?

def signup

It gets a little tricky, since we want to create either both an

account and user or neither

@account = Account.new(params[:account])
@user = User.new(params[:user])
@user.login = @account.code	# For now, we keep a 1-to-1 between

these
@user.real_name = @account.name

begin
    # TODO begin transaction
    if (@user.valid?)
    	@account.user = @user	# Don't assign until we know it is valid -

ActiveRecord sometimes saves on assign
if (@account.valid?) # We need to do this in two steps, since
@account won’t be valid without a user
@user.save!
@account.save!
# TODO end transaction
flash[:notice] = ‘Account added.’
redirect_to :action => ‘list’
return
end
end
# TODO rollback transaction
render :action => ‘new’
# TODO rescue exceptions
end
end

(Okay, I admit it, yes, this is part of a rails app…)


#5

Why do you want to do a rollback here?

It’s not to catch exceptions. It’s to make sure that no account is
saved without a user or vice versa (which would happen to be very
bad…). Especially confusing since I know AR sometimes saves
associations before we ask…


#6

removed_email_address@domain.invalid wrote:

Okay, I’ll trust you guys know better than I do.
How do I do this with a block?

http://wiki.rubyonrails.com/rails/pages/HowToUseTransactions

begin
  redirect_to :action => 'list'
  return
end
end
# TODO rollback transaction

Why do you want to do a rollback here? There is no rescue clause nor
any
indication that an error has occurred. If you use a block then you
don’t
need explicit commit and rollback. It’s handled in the method that
receives the block (#transaction).

 render :action => 'new'

TODO rescue exceptions

end
end

(Okay, I admit it, yes, this is part of a rails app…)

I know only little about RoR so there might as well be other answers.

Kind regards

robert