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 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060503/b639c607/attachment.html
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 Yandell http://9cays.com/ On 03/05/2006, at 1:13 PM, Hammed Malik wrote:> 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 > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails
Hi Pete, On 5/3/06, Pete Yandell <pete@notahat.com> 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.