Johannes Fahrenkrug
2008-Aug-19 07:51 UTC
[Rails 2.1] association.build has to be "committed" by calling association.length or association.each
Hi, I very careful about calling something a bug, so there''s of course the possibility that I''m simply doing something wrong, but I''ve encountered some strange behavior: I have a model with a has_many association, let''s call them customer and orders. When I call customer.orders.build on an existing customer that doesn''t have any orders yet, and then want to let a partial iterate over the orders to render each one, nothing happens. When, however, I call customer.orders.length or customer.orders.each {} right after build, it works. So if I have a customer that doesn''t have any orders yet and I do this: controller: @customer.orders.build view: <%= render(:partial => ''order'', :collection => @customer.orders) %> ... no order will be rendered. When I do this, the order will be rendered: controller: @customer.orders.build @customer.orders.length view: <%= render(:partial => ''order'', :collection => @customer.orders) %> I am using Rails 2.1. Is this a known issue? Am I doing something wrong/misunderstanding something? Could it possibly be related to this ticket in your old trac: http://dev.rubyonrails.org/ticket/10203 ? - Johannes -- http://blog.springenwerk.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Ryan Bigg
2008-Aug-19 08:00 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
It would be loading the associated objects without checking to see if they are a #new_record?... seems like a bug to me. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Johannes Fahrenkrug
2008-Aug-19 09:24 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
Should I open a ticket for this? On Aug 19, 10:00 am, Ryan Bigg <radarliste...@gmail.com> wrote:> It would be loading the associated objects without checking to see if > they are a #new_record?... seems like a bug to me.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Xavier Noria
2008-Aug-19 15:10 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
I am precisely documenting associations these days. I think the problem is not related to #build itself, that method adds the model to the target of the proxy just fine: fxn@feynman:~/tmp/test_associations$ cat test_build.rb post = Post.create post.comments.build puts post.comments.target.empty? fxn@feynman:~/tmp/test_associations$ script/runner test_build.rb false Looks like the issue has to do with rendering collections somehow, if you pass the target to the helper instead it works: <%= render :partial => "comment", :collection => @post.comments.target %> Note that target is a getter for @target, load_target is not involved. Looking further down, render_partial_collection has this line return " " if collection.empty? empty? is equivalent to size.zero? for association collections and #size does some stuff, so I guess we are getting close. The branch we enter does take into account new records and performs a count_records in case there was something in the database, the result is correct. In fact the flow execution goes on, but *after* that line collection.empty? is true (so the #map call afterwards does nothing and no template gets rendered). My conjecture is that the call to #size resets the proxy somehow. I may complete the walkthrough later but that''s what I''ve got by now. Next target is count_records. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Xavier Noria
2008-Aug-19 15:23 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
On Tue, Aug 19, 2008 at 5:10 PM, Xavier Noria <fxn@hashref.com> wrote:> and no template gets rendered). My conjecture is that the call to > #size resets the proxy somehow. > > I may complete the walkthrough later but that''s what I''ve got by now. > Next target is count_records.Bingo, I could continue a few minutes: def count_records # ... @target = [] and loaded if count == 0 # ... end I think the fix is just to delete that line, looks like premature optimization, though I''ve not tested whether deleting it breaks something else. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Xavier Noria
2008-Aug-19 15:39 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
Correct, a simple way to depict the underlying problem is: fxn@feynman:~/tmp/test_associations$ cat test_build.rb post = Post.create post.comments.build puts post.comments.size puts post.comments.size fxn@feynman:~/tmp/test_associations$ script/runner test_build.rb 1 0 I''ll write a patch tonight if nobody did. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Aug-19 15:47 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
On 19 Aug 2008, at 16:10, Xavier Noria wrote:> > I am precisely documenting associations these days. > > I think the problem is not related to #build itself, that method adds > the model to the target of the proxy just fine: > > fxn@feynman:~/tmp/test_associations$ cat test_build.rb > post = Post.create > post.comments.build > puts post.comments.target.empty? > fxn@feynman:~/tmp/test_associations$ script/runner test_build.rb > false > > Looks like the issue has to do with rendering collections somehow, if > you pass the target to the helper instead it works: > > <%= render :partial => "comment", :collection => > @post.comments.target %> > > Note that target is a getter for @target, load_target is not involved. > > Looking further down, render_partial_collection has this line > > return " " if collection.empty? > > empty? is equivalent to size.zero? for association collections and > #size does some stuff, so I guess we are getting close. The branch we > enter does take into account new records and performs a count_records > in case there was something in the database, the result is correct. In > fact the flow execution goes on, but *after* that line > collection.empty? is true (so the #map call afterwards does nothing > and no template gets rendered). My conjecture is that the call to > #size resets the proxy somehow. >Size looks like this: def size if @owner.new_record? || (loaded? && !@reflection.options[:uniq]) @target.size elsif !loaded? && !@reflection.options[:uniq] && @target.is_a? (Array) unsaved_records = Array(@target.detect { |r| r.new_record? }) unsaved_records.size + count_records else count_records end end Unrelated to this and maybe I''m hallucinating, but isn''t that second branch wrong ? should it not be unsaved_records = @target.select { |r| r.new_record? }) (since detect just returns the first element for which the block returns true, or nil) If we look inside count_records we can see that your conjecture is correct. count_records gets the count (reads the counter cache or executes the relevant sql query) and then it does @target = [] and loaded if count == 0 My reasoning is that this is an optimisatiohn: if you do foos.count and you get back 0 then you can assume that foos is indeed an empty array - there is no need to actually load the foos array. Of course in this case this optimisation is screwing things up. @target ||= [] and loaded if count == 0 might be more correct. Fred> I may complete the walkthrough later but that''s what I''ve got by now. > Next target is count_records. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Aug-19 15:58 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
On 19 Aug 2008, at 16:39, Xavier Noria wrote:> > Correct, a simple way to depict the underlying problem is: > > fxn@feynman:~/tmp/test_associations$ cat test_build.rb > post = Post.create > post.comments.build > puts post.comments.size > puts post.comments.size > fxn@feynman:~/tmp/test_associations$ script/runner test_build.rb > 1 > 0 > > I''ll write a patch tonight if nobody did. >Can you fix the other problem while you''re in there? currently if you do post = Post.create post.comments.build post.comments.build puts post.comments.size the output is 1 Fred --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Xavier Noria
2008-Aug-19 23:05 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
On Tue, Aug 19, 2008 at 5:39 PM, Xavier Noria <fxn@hashref.com> wrote:> Correct, a simple way to depict the underlying problem is: > > fxn@feynman:~/tmp/test_associations$ cat test_build.rb > post = Post.create > post.comments.build > puts post.comments.size > puts post.comments.size > fxn@feynman:~/tmp/test_associations$ script/runner test_build.rb > 1 > 0 > > I''ll write a patch tonight if nobody did.Here we go! http://rails.lighthouseapp.com/projects/8994/tickets/865-fix-count_records#ticket-865-1 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Xavier Noria
2008-Aug-19 23:39 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
On Tue, Aug 19, 2008 at 5:58 PM, Frederick Cheung <frederick.cheung@gmail.com> wrote:> Can you fix the other problem while you''re in there? > currently if you do > > post = Post.create > post.comments.build > post.comments.build > puts post.comments.size > > the output is 1Sure! I couldn''t reproduce this one on edge. It turns out it was fixed in this patch: http://rails.lighthouseapp.com/projects/8994/tickets/305-size-reports-incorrectly-for-collections-when-more-than-one-item-is-added-with-build The culprit was precisely the detect/select stuff you pointed out (well, I guess your example was indeed hand made to show a consequence of the detect call.) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Aug-19 23:44 UTC
Re: [Rails 2.1] association.build has to be "committed" by calling association.length or association.each
On 20 Aug 2008, at 00:39, Xavier Noria wrote:> > On Tue, Aug 19, 2008 at 5:58 PM, Frederick Cheung > <frederick.cheung@gmail.com> wrote: > >> Can you fix the other problem while you''re in there? >> currently if you do >> >> post = Post.create >> post.comments.build >> post.comments.build >> puts post.comments.size >> >> the output is 1 > > Sure! > > I couldn''t reproduce this one on edge. It turns out it was fixed in > this patch: > > http://rails.lighthouseapp.com/projects/8994/tickets/305-size-reports-incorrectly-for-collections-when-more-than-one-item-is-added-with-build >Ah, awesome. Sorry for the false alarm! Fred> The culprit was precisely the detect/select stuff you pointed out > (well, I guess your example was indeed hand made to show a consequence > of the detect call.) > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---