我试图想出一种在页面上使用reddit样式嵌套注释的有效方法。我已经按照我想要的方式设置了一切。但是,我很难弄清楚如何以有效的方式呈现评论。请参阅我目前的部分内容:
#_comment_list.html.erb
<div class="comment-list">
<h2>Comments</h2>
<ul>
<% @post.comments.each do |c| %>
<% byebug %>
<li><%= c.body %></li>
<% unless c.is_deleted == true %>
<%= render partial: "shared/comment_form", :locals => { commentable_type: c.class.name, commentable_id: c.id, post: @post.id } if current_user %>
<% end %>
<ul>
<% c.comments.each do |d| %>
<li><%= d.body %></li>
<% unless d.is_deleted == true %>
<%= render partial: "shared/comment_form", :locals => { commentable_type: d.class.name, commentable_id: d.id, post: @post.id } if current_user %>
<% end %>
<% end %>
</ul>
<% end %>
</ul>
</div>
显然,这只会呈现一组儿童评论,如下所示:
Post
Comment
Child Comment
Child Comment
Comment
...
我设计了一个空白,设计明智,如何将孩子评论的孩子渲染多次,因为他们需要嵌套。
Post
Comment
Child Comment
Grandchild Comment
Great Grandchild Comment
Great Grandchild Comment
Child Comment
Comment
...
如果有人能指出我去哪儿方向,我将不胜感激。
以下是有关我的模型和关联的一些信息,如果它有助于提出解决方案。
# Comment.rb
class Comment < ApplicationRecord
validates_presence_of :body
# validates :user_id, presence: true
belongs_to :user
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable
def find_parent_post
return self.commentable if self.commentable.is_a?(Post)
self.commentable.find_parent_post # semi recursion will keep calling itself until it .is_a? Post
end
end
# Post.rb
class Post < ApplicationRecord
validates :user_id, presence: true
validates :forum_id, presence: true
belongs_to :user
belongs_to :forum
has_many :comments, as: :commentable
end
create_table "comments", force: :cascade do |t|
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "commentable_id"
t.string "commentable_type"
t.integer "user_id"
t.boolean "is_deleted", default: false, null: false
end
create_table "forums", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_forums_on_user_id", using: :btree
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "description"
t.integer "user_id"
t.integer "forum_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["forum_id"], name: "index_posts_on_forum_id", using: :btree
t.index ["user_id"], name: "index_posts_on_user_id", using: :btree
end
答案 0 :(得分:2)
两种方法:
创建一个引用子注释的部分,例如:
# comments/_show.html.erb
<% depth ||= 0 %>
<div class="comment" style="padding-left: <%= 16 * depth %>px;">
<%= comment.text %>
<% comment.children.each do |c| %>
<%= render partial: "comments/show", locals: { comment: c, depth: depth + 1 } %>
<% end %>
</div>
或者您可以修改您的注释模型以在数据库级别进行自然嵌套,并一次查询/命令/缩进它们。这更复杂,但它非常强大且非常易于使用。
在评论表中添加tree_left
,tree_right
和depth
列(所有正整数)。索引tree
列。
tree_left
和tree_right
是相互唯一的,包含从1到(记录数* 2)的每个数字。这是一个示例树:
test# select id, text, parent, tree_left, tree_right, depth from comments order by tree_left;
+----+----------------------------+-----------+-----------+------------+-------+
| id | text | parent | tree_left | tree_right | depth |
+----+----------------------------+-----------+-----------+------------+-------+
| 1 | Top Level Comment | NULL | 1 | 30 | 0 |
| 2 | Second Level | 1 | 2 | 29 | 1 |
| 3 | Third Level 1 | 2 | 3 | 20 | 2 |
| 5 | Fourth Level 1 | 3 | 4 | 9 | 3 |
| 12 | Fifth Level 4 | 5 | 5 | 6 | 4 |
| 13 | Fifth Level 5 | 5 | 7 | 8 | 4 |
| 6 | Fourth Level 2 | 3 | 10 | 19 | 3 |
| 8 | Fifth Level | 6 | 11 | 18 | 4 |
| 9 | Sixth Level 1 | 8 | 12 | 13 | 5 |
| 10 | Sixth Level 2 | 8 | 14 | 15 | 5 |
| 11 | Sixth Level 3 | 8 | 16 | 17 | 5 |
| 4 | Third Level 2 | 2 | 21 | 28 | 2 |
| 7 | Fourth Level 3 | 4 | 22 | 27 | 3 |
| 14 | Fifth Level 6 | 7 | 23 | 24 | 4 |
| 15 | Fifth Level 7 | 7 | 25 | 26 | 4 |
+----+----------------------------+-----------+-----------+------------+-------+
使用depth = 0
,tree_left = (current largest tree_right + 1)
和tree_right = (current largest tree_right + 2)
插入顶级评论。
使用depth = parent.depth + 1
,tree_left = parent.tree_right
和tree_right = parent.tree_right +
插入子评论。然后,运行:
UPDATE comments SET tree_left = tree_left + 2 WHERE tree_left >= #{parent.tree_right}
UPDATE comments SET tree_right = tree_right + 2 WHERE tree_right >= #{parent.tree_right}
评论A
是评论B
的孩子,当且仅当:
A.tree_left > B.tree_left
和A.tree_right < B.tree_right
。
所以它的工作方式是你可以让树中的所有孩子都属于评论&#34; XYZ&#34;使用此查询:
Select * from comments where tree_left >= #{XYZ.tree_left} AND tree_right <= #{XYZ.tree_right} ORDER BY tree_left
。
要获得评论的所有父母,请使用相反的符号:
Select * from comments where tree_left <= #{XYZ.tree_left} AND tree_right >= #{XYZ.tree_right} ORDER BY tree_left
。
在条件中包含=
可确定是否包含用于生成查询的注释。
tree_left的顺序非常重要,它将它们置于嵌套树顺序中。然后在您的视图中,您可以直接遍历此列表,并按其深度缩进它们。
有关此tree_left和tree_right内容工作原理的更多信息,请查看本文的嵌套集理论部分:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
答案 1 :(得分:1)
递归就是你要找的东西。这是一个棘手的例子:http://benjit.com/rails/2015/04/01/rendering-partials-with-layouts-recursively/
这是一些示例代码
#_post.html.erb
<%= render partial: 'comment_list', locals: {commenabel: @post} %>
这是递归的部分:
#_comment_list.html.erb
<div>
<%= commentable.to_s %>
</div>
<ul>
<% commentable.comments.each do |comment| %>
<li>
<%= render partial: 'comment_list', locals: {commentable: comment} %>
</li>
<% end %>
</ul>