我正在尝试找出一种在页面上使用 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
最佳答案
两种方式:
为子评论创建一个引用自身的部分,例如:
# 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>
或者您可以修改 Comment 模型以在数据库级别具有自然嵌套,并一次查询/排序/缩进它们。这更复杂,但它非常强大且非常易于使用。
添加 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
是评论的 child B
当且仅当:
A.tree_left > B.tree_left
, 和 A.tree_right < B.tree_right
.
所以它的工作方式是你可以通过这个查询得到属于评论“XYZ”的树中的所有 child :
Select * from comments where tree_left >= #{XYZ.tree_left} AND tree_right <= #{XYZ.tree_right} ORDER BY tree_left
.
要获取评论的所有 PARENTS,请使用相反的符号:
Select * from comments where tree_left <= #{XYZ.tree_left} AND tree_right >= #{XYZ.tree_right} ORDER BY tree_left
.
包含 =
在条件中确定是否包含用于生成查询的评论。
tree_left 的顺序很重要,它将它们置于嵌套树顺序中。然后在您的 View 中,您可以直接遍历此列表并按深度缩进它们。
有关为什么这个 tree_left 和 tree_right 东西起作用的更多信息,请查看本文的嵌套集理论部分:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
关于ruby-on-rails - rails 5 : Render a div for each child object in a collection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40896240/