2016-11-30 34 views
1

我試圖找出一種有效的方法來在頁面上嵌入reddit樣式的註釋。我已經按照自己的意願建立了一切。但是,我很難弄清楚如何以有效的方式呈現評論。見我的電流以下部分:Rails 5:爲集合中的每個子對象呈現div

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

回答

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_rightdepth列添加到您的評論表(所有正整數)。索引tree列。

tree_lefttree_right是相互唯一的並且包含從1到(Number of records * 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 = 0tree_left = (current largest tree_right + 1)tree_right = (current largest tree_right + 2)頂層評論。

插入與depth = parent.depth + 1,tree_left = parent.tree_righttree_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_leftA.tree_right < B.tree_right

所以這個工作的方式是你可以得到所有的孩子在屬於評「XYZ」與此查詢樹:

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/

+0

這是一個超級有益的解釋。任何學習SQL技巧的機會對我來說都是一個加分。謝謝你,它確實幫了你。 – Antonio

1

遞歸是你在找什麼。這裏有一個railsy例如: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> 
相關問題