如何在rails中正确呈现嵌套注释?

时间:2018-02-15 03:09:38

标签: ruby-on-rails ruby erb

我试图在rails 5应用程序中使嵌套注释正常工作并遇到很多困难。

我正在建立一个问答网站,我有一个Acomment模型,其中有评论属于答案,然后有评论属于其他评论:

class Acomment < ApplicationRecord
  belongs_to :answer
  belongs_to :user
  belongs_to :parent, class_name: "Acomment", optional: true
  has_many :replies,
           class_name: "Acomment", foreign_key: :parent_id, dependent: :destroy
end

我想显示所有评论,然后是所有回复评论,回复回复等等。但我无法弄清楚如何使嵌套正常工作。

在我看来,在每个循环中,我都在渲染_comment.html.erb部分:

<% answer.acomments.each do |comment| %>
  <%= render :partial=>"comment", :object=>comment %>
<% end %>

然后,在我的_comment.html.erb部分内部,我显示评论,回复链接,然后呈现部分回复评论:

<div>
  <%= comment.body %>
  <%= link_to "Reply", new_acomment_path(:parent_id => comment, :answer_id => comment.answer) if comment.parent_id.blank? %>

  <%= render partial: "reply", collection: comment.replies %>
</div>

这里是_reply.html.erb部分:

<%= reply.body %>
<%= link_to "Reply", new_acomment_path(:parent_id => reply, :answer_id => reply.answer) %>

我遇到了两个问题:

1)当我渲染第一个部分时,它不仅渲染了注释,而且还同时呈现了回复(因为它们也是注释)。

2)当我渲染第二个部分(回复)时,它们不会嵌套在它们应该的注释中。一切都搞不定了。

编辑: 我希望看到这个:

Comment 1 
  Comment on Comment 1 
    Comment on Comment on Comment 1 
Comment 2 

但相反,这就是我所看到的:

Comment 1 
Comment on Comment 1 
Comment 2 
Comment on Comment 1 
Comment on Comment on Comment 1 
Comment on Comment on Comment 1

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

正如Taryn所写,你首先需要过滤没有parent_id的评论,这意味着他们是对答案的第一级评论。

视图/答案/ show.html.erb

<%= @answer.text %>
<h4>Comments</h4>
<% @answer.acomments.parents.each do |comment| %>
  <%= render :partial=>"comment", locals: { comment: comment } %>
<% end %>

然后你需要一个递归方法:

视图/ acomments / _comment.html.erb

<div>
  <%= comment.body %>
  <%= link_to "Reply", new_acomment_path(:parent_id => comment, :answer_id => comment.answer) if comment.parent_id.blank? %>

  <% comment.replies.each do |reply|
    <%= render :partial => "comment", locals: { comment: reply } %>
  <% end %>
</div>

您需要提供一些缩进,以便明确评论之间的层次结构。

答案 1 :(得分:1)

对于问题的第一部分,您可能需要一些范围来帮助您区分“父评论”(即不是答复的评论)和“儿童评论”(答复)。

类似的东西:

class Acomment < ApplicationRecord
  belongs_to :answer
  belongs_to :user
  belongs_to :parent, class_name: "Acomment", optional: true
  has_many :replies, class_name: "Acomment", foreign_key: :parent_id, dependent: :destroy

  scope :is_parent, where(parent_id: nil)
  scope :is_child, where("parent_id IS NOT NULL")
end

你可以使用下面的这些来渲染主循环中的父母......意图每个父母都会渲染自己的孩子。

<% answer.acomments.is_parent.each do |comment| %>
    <%= render :partial=>"comment", :object=>comment %>
<% end %>

写下你的第二个问题 - 我需要更多信息 - 我会在上面的评论中提出。

后:

所以...我对正在发生的事情的猜测是:你只是得到了所有的评论(正如你所提到的)并且它们被显示在外部循环中(而不仅仅是在外部循环中显示的父项)并且它们按顺序排列,因为这是评论的数据库顺序。

由于partials中的默认命名约定,内部循环中实际上没有显示任何内容。

如果在部分中使用collection - Rails会将每个项目提供给部分...然后在部分名称后面命名局部变量。在这种情况下,您尝试呈现名为“reply”的部分,但传入一组注释...因此partial将查找名为“reply”的变量。

我建议您重复使用已经使用的相同“评论”部分,而是以这种方式呈现:

<div>
  <%= comment.body %>
  <%= link_to "Reply", new_acomment_path(:parent_id => comment, :answer_id => comment.answer) if comment.parent_id.blank? %>

  <%= render partial: "comment", collection: comment.replies %>
</div>

它将是递归的(就像Pablo的建议一样),因此通过缩进每一组子注释来呈现注释线程。

看看你与pablo的谈话...... parents可能是一个范围的坏名字......听起来它可能会干扰一个名为同样的东西的ruby方法类层次结构...所以也许这是一个坏名字 - 因此我将重命名范围。