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)
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.