Make nested comment with gem closure_tree
Bài đăng này đã không được cập nhật trong 3 năm
Demo mà mình sẽ làm trong bài viết này là nested comment, mình sẽ tiếp tục làm demo dựa trên source code cũ bài viết trước của mình, sau khi hoàn thành nó sẽ như thế này nhé
1. Cài đặt
gem "closure_tree"
Thêm vào Gemfile rồi bundle install
nhé
2. Chuẩn bị cho demo
Những gì bạn cần là một demo comment ajax.
$ rails g model Comment content:text user:references post:references
$ rake db:migrate
Khai báo trong routes.rb
resources :comments, only: [:create, :destroy]
Khai báo trong app/controllers/comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:destroy]
def create
@comment = Comment.create! comment_params
respond_to do |format|
format.html{redirect_to :back}
format.js
end
end
def destroy
@comment.destroy
redirect_to :back
end
private
def comment_params
params.require(:comment).permit :post_id, :user_id, :content
end
def set_comment
@comment = Comment.find_by id: params[:id]
end
end
Khai báo trong app/controllers/posts_controller.rb
def show
@comment = Comment.new
@comments = @post.comments
end
Khai báo
app/views/posts/show.html.erb
,
app/views/comments/create.js.erb
,
app/views/comments/_comment.html.erb
Bạn có thể xem thêm ở đây: https://github.com/ptnk1995/vote_demo/pull/2/files
3. Thêm nested comment
$ rails g migration add_parent_id_to_comments parent_id:integer
$ rake db:migrate
parent_id sẽ lưu id của bình luận cha (nếu không có cha thì giá trị là null)
Chúng ta cũng sẽ tạo thêm 1 bảng mới để lưu hệ thống phân cấp bình luận.
$ rails g migration create_comment_hierarchies
Rồi khai báo trong migration này như sau:
class CreateCommentHierarchies < ActiveRecord::Migration[5.0]
def change
create_table :comment_hierarchies, :id => false do |t|
t.integer :ancestor_id, :null => false # ID of the parent/grandparent/great-grandparent/... comments
t.integer :descendant_id, :null => false # ID of the target comment
t.integer :generations, :null => false # Number of generations between the ancestor and the descendant. Parent/child = 1, for example.
end
# For "all progeny of…" and leaf selects:
add_index :comment_hierarchies, [:ancestor_id, :descendant_id, :generations],
:unique => true, :name => "comment_anc_desc_udx"
# For "all ancestors of…" selects,
add_index :comment_hierarchies, [:descendant_id],
:name => "comment_desc_idx"
end
end
rồi $ rake db:migrate
nhé
Để nó có thể nested, khai báo cần thiết là:
# models/comment.rb
acts_as_tree order: "created_at ASC"
Và cần có những sự khai báo khác, bạn có thể xem thêm ở đây: https://github.com/ptnk1995/vote_demo/pull/3/files Trong pull này điều mình muốn note lại với bạn là:
limit_depth: n
: giới hạn cấp tối đa của nested là thứ n
<%= comments_tree_for @supports.comments_tree.hash_tree(limit_depth: 5),
@post, @supports.comment %>
- Muốn hiển thị tất cả những bình luận lồng nhau, để giải quyết cho vấn đề hiển thị phức tạp thế này thì khai báo helper là điều cần thiết
module CommentsHelper
def comments_tree_for comments, post, comment_new
safe_join(comments.map do |comment, nested_comments|
render(comment, post: post,
comment_new: comment_new) + tree(nested_comments, post)
end)
end
def tree nested_comments, post
unless nested_comments.empty?
content_tag :div,
comments_tree_for(nested_comments, post, Comment.new), class: "replies"
end
end
end
- Nếu bạn muốn khi xóa comment cha, thì những comment con cũng được xóa theo như comment facebook thì gem closure_tree có hỗ trợ cho bạn phương thức:
def destroy
@comment.descendants.each do |comment_des|
comment_des.destroy
end
@comment.destroy
redirect_to :back
end
descendants
để lấy được các comment con của nó
4. Tham khảo
Muốn tìm hiển thêm về các phương thức, cũng như cách sử dụng của gem Closure_tree bạn có thể xem thêm ở đây: Doc gem Closure_tree
5. Source Code:
All rights reserved