ruby-on-rails - rails 5 : Render a div for each child object in a collection

标签 ruby-on-rails ruby ruby-on-rails-5

我正在尝试找出一种在页面上使用 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_rightdepth列到您的评论表(所有正整数)。索引 tree列。

tree_lefttree_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/

相关文章:

ruby-on-rails - 包括 collection_select 助手的空白和默认值

ruby-on-rails - 在 ruby​​ 中运行多个命令行

ruby-on-rails - 捕获 Rails View block 时的差异

ruby-on-rails - 在两个日期时间之间迭代,步长为一小时

ruby-on-rails - Rails,如何通过created_at 对事件记录数组进行排序

ruby-on-rails - 带有 splat 参数的 Rake 任务

ruby-on-rails - AWS S3 Ruby url_for 响应 header (自定义文件名和文件类型)

Ruby 正则表达式键搜索

ruby-on-rails - 嵌套资源的 Controller 测试

ruby-on-rails - 无法将本地对象传递给 Rails 3 中的嵌套部分