Database transactions

Hello,

I have an application where I need to create two records in a database
transaction.

ie:

begin
User.transaction(user) do
User_details.transaction(user_details) do
user.save
user_details.save
end
end
end

rescue
flash[:notice] “Insert rolled back… but why…??”
end

From reading the Agile book, I gather that once I wrap the request in a
transaction I loose the validation state, so I have no easy what of
knowing what went wrong.

I am just wonder what the best practise is…??

Is this something people would recommend?

user.validate
if user.errors.count == 0
user_details.validate
if user_details.errors.count == 0
perform transaction_routine(user, user_details)
end
end

rgds,

  • matt.

On Aug 8, 2006, at 8:14 AM, Matt S. wrote:

Not clear on your actual problem, but you could
simplify the code as below. As written, I’m not
sure that rescue clause was valid at all.

end

– Tom M.

On 8 Aug 2006, at 16:14, Matt S. wrote:

    user.save

From reading the Agile book, I gather that once I wrap the request
in a
transaction I loose the validation state, so I have no easy what of
knowing what went wrong.
You only lose the validation if you also have the transaction roll
back the active record object as well as the database.

If you do this:

begin
User.transaction(user) do
Use.transaction do
User_details.transaction(user_details) do
user.save
You probably want to do
user.save! here
The transaction aborts if an exception is thrown, not if the save
fails. So you need to use save! to get the RecordInvalid exception
thrown out.

    user_details.save
  end
end

end

rescue
user has not been rolled back, so contains all the errors from when
it was saved

flash[:notice] "Insert rolled back... but why..??"

end

Is this something people would recommend?

user.validate
if user.errors.count == 0
user_details.validate
if user_details.errors.count == 0
perform transaction_routine(user, user_details)
end
end

Use the transaction if you need thread-safety (you don’t need thread
safety if you are only serving with a single process, but that
doesn’t mean it’s not worth thinking about upfront). The transaction
in itself won’t magically make things threadsafe though; you need to
think carefully about your failure scenarios and whether all of them
cause an exception. For example, your case above creates a user
record, then a user_details record. Suppose a separate thread updates
the user record before the user_details record has been saved. Is
this a problem?

Ben


Ben B. - Director
Airsource Ltd
Tel: 01223 708370 / 07786 916043

On Aug 8, 2006, at 8:14 AM, Matt S. wrote:

end

end
(Transactions are per database connection, not per class or object,
so you only need to call it once - the transaction method is
available on all of them for convenience.)

def update
User.transaction do
@user.save!
@user_details.save!
end
rescue ActiveRecord::RecordInvalid
flash.now[:error] = “error saving #{@user.name}”
render :action => ‘edit’
end

<%= error_messages_for ‘user’ %>
<%= error_messages_for ‘user_details’ %>

Though it’s likely more appropriate to manage this in your model,
particularly if one object is dependent on the other.

jeremy