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
 
     
     
    