Background
I was learning from rails guide when I encountered this queer behaviour cause by build
So in the guide I was making a blog where posts had comments section. In the guide they made the comments posted appear before the comments form for adding new comments. Somehow I wanted to tried the other way around (comments form first). However when I did that, additional empty tags <h4></h4><p></p>
were rendered.
Initially I thought it was rendering an empty comment from the model but after running
<%= @article.comments.count %> # => 2 gives expected comments count
Now comes the queer part. When I inverted the order as per the guide, comments form first then comments, the empty tags disappeared and everything works fine.
Question
- How do I fix it? (solved)
- Why does changing the order of the form and the comments cause the 'bug' to disappear?
View
#This works
#comments
<h3>Comments</h3>
<%= render @article.comments %>
#comments form
<h3>Add a comment!</h3>
<%= render 'comments/form' %>
#But not this
#comments form
<h3>Add a comment!</h3>
<%= render 'comments/form' %>
#comments
<h3>Comments</h3>
<%= render @article.comments %>
Partials
comment partial
<h4>
<%= comment.commenter %>
</h4>
<p>
<%= comment.body %>
</p>
comment form partial
<%= form_for([@article, @article.comments.build]) do |f| %>
<p class="commenter">
<%= f.label :commenter %><br>
<%= f.text_field :commenter %>
</p>
<p class="text">
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Summary of the answers/findings
Solution
Comment.new
is used instead of @article.comments.build
as .build
is making an extra instance (is this a bug?)
new
vs build
According to Kris
.new method has changed since Rails > 3.2.13
new
and build
are the same. build
is merely an alias
Comparison of size
vs count
I found this SO post about count vs size and the recommended reading in that post. In case someone passes by and wants to know more about the subtlety.
In essence (from the SO post) and @Jiří Pospíšil answer
count
sends a query to the db to retrieve the number of elements. In this context @article.comments.count returns the number of comments in the DB
length
give the number of comments loaded into memory that said, memory and db data might not be the same. Some elements in the memory might be new.
size
as @Jiří Pospíšil will give the number of elements in the collection if it has been loaded (like length
) else works like count
and sends a SQL COUNT query
#when .build was used
<%= @article.comments.length %> # => 2
<%= @article.comments.count %> # => 1
<%= @article.comments.size %> # => 2
and when the proposed solution Comment.new
was used, all methods return 1 which is consistent with what this guy said
EDIT
Stated questions more explicitly
added summary of answers/discussion