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.
> 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.
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.
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
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
> 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:
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.)
>
> On Tue, Aug 19, 2008 at 5:58 PM, Frederick Cheung
> <frederic...@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