Perplexing nested transaction issue


#1

I’ve been struggling with a strange nested transaction problem for a
while.
I have a two objects with the following relationships:

Mail has_many :recipients
Recipients belong_to :mail

I’d like to update the status of the Mail object while sending mails for
each of it’s recipients. Following is a simplified example that I’m
having
problems with:

def send_mail
@mail = Mail.find params[:id]
@recipients = Recipient.find_all_by_mail_id @mail.id
processed = 0
logger.info “__Loop Start”
@recipients.each do |recipient|
recipient.status = ‘ok’
logger.info “==Recipient Saved - #{recipient.save}”
@mail.status = (processed += 1)
@mail.save
logger.info “–Mail Saved”
end
logger.info “__Loop End”
render :text => “done”
end

The problem is that with the above setup, the status of the recipient
isn’t
updated within the .each loop. Looking at the log, I noticed that the
UPDATE
statement which would update the recipient status is missing. Through
trial
and error I found that if I remove the line that saves the mail status
within the loop, the recipients are saved correctly. It looks like
there’s
an issue with nested transactions but I can’t figure out what’s going
on.

Following is the relevan section of the log formatted for clarity. I’ve
pointed out the spots where the update statement for recipients is
missing
with ??? UPDATE RECIPIENT MISSING:

__Loop Start
SQL (0.000315) BEGIN
Mail Load (0.000446) SELECT * FROM mails WHERE (mails.id = 62)
LIMIT
1
??? UPDATE RECIPIENT MISSING
SQL (0.000180) COMMIT
==Recipient Saved - false
SQL (0.000157) BEGIN
SQL (0.002060) SELECT count(*) AS count_all FROM recipients
WHERE (
recipients.mail_id = 62)
Mail Update (0.000386) UPDATE mails SET … status = 1 WHERE
id =
62
Recipient Load (0.004454) SELECT * FROM recipients WHERE (
recipients.mail_id = 62) ORDER BY name
SQL (0.001372) COMMIT
–Mail Saved

SQL (0.000273)   BEGIN
  Mail Load (0.000559)   SELECT * FROM mails WHERE (mails.id = 62) 

LIMIT
1
??? UPDATE RECIPIENT MISSING
SQL (0.000166) COMMIT
==Recipient Saved - false
SQL (0.000099) BEGIN
SQL (0.002693) SELECT count(*) AS count_all FROM recipients
WHERE (
recipients.mail_id = 62)
Mail Update (0.000372) UPDATE mails SET … status = 2 WHERE
id =
62
SQL (0.000868) COMMIT
–Mail Saved
__Loop End

Any tips will be appreciated. Thanks


#2

Hammed,

The fact that recipient.save is returning false indicates that the
validations for the recipient are failing. Try having a look at
recipient.errors after the save to work out what’s happening.

Pete Y.
http://9cays.com/


#3

Hi Pete,

On 5/3/06, Pete Y. removed_email_address@domain.invalid wrote:

The fact that recipient.save is returning false indicates that the
validations for the recipient are failing. Try having a look at
recipient.errors after the save to work out what’s happening.

I printed out the errors for the recipient object and didn’t find any.
For some reason, the update statement for recipients never gets called
if I like the update statement is never called if I save the @mail
object afterwards. If I comment out the part that saves @mail,
recipient gets updated.