.build 的奇怪行为

Strange behaviour with .build

背景

当我遇到这种由 build

引起的奇怪行为时,我正在向 rails guide 学习

所以在指南中,我正在创建一个博客,其中 posts 有评论部分。在指南中,他们让评论 posted 出现在用于添加新评论的评论表单之前。不知何故,我想尝试另一种方式(首先形成评论)。但是,当我这样做时,会呈现额外的空标签 <h4></h4><p></p>

最初我认为它正在渲染模型中的空注释,但在运行后

<%= @article.comments.count %> # => 2 gives expected comments count

酷儿部分来了。当我按照指南颠倒顺序时,评论先形成然后评论, 空标签消失了,一切正常。

问题

  1. 我该如何解决? (已解决)
  2. 为什么更改表单和注释的顺序会导致 'bug' 消失?

查看

#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 %>

部分

评论部分

<h4>
  <%= comment.commenter %>
</h4>
<p>
  <%= comment.body %>
</p>

部分评论形式

<%= 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 %>

摘要answers/findings

解决方案

使用

Comment.new 而不是 @article.comments.build 因为 .build 正在创建一个额外的实例(这是一个错误吗?)

new 对比 build

根据克里斯

.new method has changed since Rails > 3.2.13

newbuild是一样的。 build 只是一个别名

sizecount

的比较

我在那个 post 中找到了这个 SO post about count vs size and the recommended reading。以防有人路过,想知道更多的精妙之处。

本质上(来自 SO post)和@Jiří Pospíšil 的回答 count 向数据库发送查询以检索元素数。在此上下文中@article.comments.count returns 数据库中的评论数

length 给出加载到内存中的注释数量,表示内存和数据库数据可能不相同。内存中的一些元素可能是新的。

size 因为@Jiří Pospíšil 将给出集合中元素的数量(如果已加载)(如 length),否则工作方式类似于 count 并发送 SQL COUNT 个查询

#when .build was used
<%= @article.comments.length %> # => 2
<%= @article.comments.count %> # => 1
<%= @article.comments.size %> # => 2

并且当使用建议的解决方案Comment.new时,所有方法return 1 与this guy said

一致

编辑

更明确地陈述问题
添加了 answers/discussion

的摘要
<%= form_for([@article, @article.comments.build]) do |f| %>

@article.comments.build 部分将创建一个新的 Comment 并将其添加到 @article.comments 集合中。稍后,您遍历集合,这就是为什么多了一个集合。如果您这样做,您实际上可以看到它的发生。

<%= form_for([@article, @article.comments.build(commenter: "Hello!")]) do |f| %>

要解决此问题,您需要创建一个 Comment 但不将其与集合相关联。使用 Comment.new 而不是 @article.comments.build 应该就足够了,因为记录本身并不重要。

请注意,您看到正确数量的评论 (@article.comments.count) 的原因是通过 build 创建的评论尚未保存到数据库并且 #count始终执行 COUNT 查询,无论集合是否已加载。您可以使用 #size 来查看额外的评论 (@article.comments.size).

问题是您的评论表单部分调用了 @article.comments.build,这除了构造一个新的 Comment 实例之外还将此实例添加到集合中。这就是您看到额外评论的原因。请尝试使用 @article.comments.new

另请参阅:Build vs new in Rails 3

编辑

我刚刚发现 .new 方法自 Rails > 3.2.13 以来发生了变化。由于您已将 post 标记为 Rails-4,因此我提出的解决方案不起作用。相反,请尝试按照 here 的建议使用 @article.comments.scoped.new