Reddit-style nested/threaded/indented comments for Rails?
Asked Answered
S

4

15

I'm wondering if someone has already built a system for threaded comments (for lack of a better term) in Rails or if I need to build it myself.

In case it's not clear, what I'm referring to is a comment system like Reddit's that automatically indents replies so that they appear like branches of a tree (preferably with voting just as Reddit does).

If someone could point me to code that does this, it would be greatly appreciated.

Or perhaps there is an open source project that includes this functionality.

So far I have not been able to find one in Rails.

Also, would it be better to ask this on a Rails forum and, if so, which one? (I'm new to Rails)

Swagman answered 21/1, 2009 at 2:34 Comment(0)
T
40

Using the acts_as_tree plugin should make this fairly easy to implement. Install it using

ruby script/plugin install acts_as_tree

app/models/comment.rb

class Comment < ActiveRecord::Base
  acts_as_tree :order => 'created_at'
end

db/migrate/20090121025349_create_comments.rb

class CreateComments < ActiveRecord::Migration
  def self.up
    create_table :comments do |t|
      t.references :parent
      t.string :title
      t.text :content
      ...
      t.timestamps
    end
  end

  def self.down
    drop_table :comments
  end
end

app/views/comments/_comment.html.erb

<div id="comment_<%= comment.id %>">
  <h1><%= comment.title %></h1>
  <%= comment.content %>
  <%= render :partial => 'comments/comment', :collection => comments.children %>
</div>

app/views/comments/show.html.erb

<div id="comments">
  <%= render :partial => 'comments/comment', :object => Comment.find(params[:id]) %>
</div>

The magic happens in show.html.erb when it calls <%= render :partial => 'comments/comment', :object => Comment.find(params[:id]) %>, this will cause the partial to recursively render all children comments. If you want a limit to the depth, you can do it in the partial or in the model.

Edit:
This will leave you with all the comments with the same spacing in the HTML for every depth. If you want to produce easy to read HTML, just use render(...).gsub(/^/, "\t") this will work recursively as well producing nicely indented HTML.

I combined it into my own method in app/helpers/application_helper.rb

def indented_render(num, *args)
  render(*args).gsub(/^/, "\t" * num)
end

So now you can call <%= indented_render 1, :partial => 'comments/comment', ... %>

Edit:
Fixed missing closing </h1> tag in the example.

Towrope answered 21/1, 2009 at 3:10 Comment(4)
I believe you're missing a closing h1 in the comment title. Other than that, awesome answer! Thanks! :)Knockknee
Holy cow! Great answer! This really helped me out with a project. I never thought about using acts_as_tree.Trumantrumann
I am trying to use acts_as_tree but I can't get indented_render to work. this is what I am doing. What am I doing wrong?Eolic
How many sql statements does this create when you try to grab the comments? Is this method scalable?Victuals
F
1

The links to the ActsAsTree documentation as given by Hector and Samuel seem to be broken. You can get the docs at

 
http://web.archive.org/web/20061011101510/http://wiki.rubyonrails.org/rails/pages/ActsAsTree

(I used a pre tag as the linked kept displaying wrong for some reason).

Fedora answered 19/6, 2009 at 5:23 Comment(0)
I
1

There is a has_threaded_comments gem, never used it, but it looks like it does exactly this: https://github.com/aarongough/has_threaded_comments

Immerse answered 19/2, 2011 at 0:19 Comment(0)
A
0

Did you tried acts_as_tree plugin on your model? It's a official ActiveRecord component.

http://wiki.rubyonrails.org/rails/pages/ActsAsTree

Alternant answered 21/1, 2009 at 2:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.