Database Transactions

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???)

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.

···

--
Posted via http://www.ruby-forum.com/\.

Andreas Schwarz 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

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...)

listrecv@gmail.com 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

  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

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

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...