Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested comments and replies in Ruby on Rails

I am working on my first project in ruby on rails and need to implement comments and replies functionality on it. I am facing of displaying replies under each comment as well as if any reply has child replies they need to display under it. The structure will be some how as follow.

first comment
       Reply to first comment
            reply to first comment first reply
       reply to first  comment
Second comment
      Reply to second comment

and this nested structure continues. I have only one table for these all comments with parent key to treat as a reply. The table structure is as follow

Id | Comment_body | parent_id | user_id | project_id
1      comment                        2          2
2      comment/reply   1              2          2
3      comment/reply   2              2          2

this second comment is treated as a reply to the first comment and id 3 comment is treated as a reply to the first reply of the first comment. kindly help regarding this nested structure that how I can manage it in the best way. The comment table also has an association with the project table and user table. suggest the best way without gem as I already tried many of them but they are limited in-depth level.

like image 584
Muhammad Azam Avatar asked Jan 19 '16 23:01

Muhammad Azam


1 Answers

We've done this before. There's also a RailsCast about it..

enter image description here

The term you're looking for is recursion - self replicating.


Use acts_as_tree: You can do this with has_many / belongs_to

#app/models/comment.rb
class Comment < ActiveRecord::Base
   belongs_to :project
   belongs_to :parent,  class_name: "Comment" #-> requires "parent_id" column
   has_many   :replies, class_name: "Comment", foreign_key: :parent_id, dependent: :destroy
end

This will allow the following:

#app/views/projects/show.html.erb
<%= render @project.comments %>

#app/views/comments/_comment.html.erb
<%= comment.body %>
<%= render comment.replies if comment.replies.any? %>

The recursion occurs with render comment.replies -- it will continue to loop through the replies until there are no more. Although this will take some DB processing to do, it will display the comments with nesting.

--

If you wanted to add a reply etc, you just have to populate the "parent" ID:

#config/routes.rb
resources :projects do 
   resources :comments #-> url.com/projects/:project_id/comments/:id
   end
end

#app/views/comments/_comment.html.erb
<%= form_for [comment.project, comment.new] do |f| %>
   <%= f.hidden_field :parent_id, comment.parent.id %>
   <%= f.text_field :body %>
   <%= f.submit %>
<% end %>

The above will submit to the comments#create action:

#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
   def create
      @project = Project.find params[:project_id]
      @comment = @project.comments.new comment_params
   end

   private

   def comment_params
      params.require(:comment).permit(:parent_id, :body)
   end
end
like image 174
Richard Peck Avatar answered Oct 05 '22 03:10

Richard Peck