Rails 4 - All nested polymorphic comments showing on every page, not on individual pages

442 Views Asked by At

I'm in the process of learning Rails and trying to create a site with nested polymorphic comments.

I have been following this tutorial http://www.tweetegy.com/2013/04/create-nested-comments-in-rails-using-ancestry-gem/ as well as some RailsCasts (262-trees-with-ancestry and 154-polymorphic-association).

I have successfully managed to create nested polymorphic comments (when I check rails console for each comment). However, the problem I'm having is outputting the comments. They all show up on every resources' show page, not on the relevant show page. In other words, all of the comments are showing on /videos/1 and videos/2 and lessons/1 and lessons/3 (the same comments are showing on every page).

I suspect my problem is in the comments_helper.rb or /lib/commentable.rb file, however I haven't had any luck debugging the problem.

Routes

config/routes.rb

  devise_for :users

  resources :videos do
    resources :comments
  end

  resources :lessons do
    resources :comments
  end

Controllers

app/controllers/comments_controller.rb

class CommentsController < ApplicationController
  def new
    @parent_id = params.delete(:parent_id)
    @commentable = find_commentable
    @comment = Comment.new( :parent_id => @parent_id, 
                            :commentable_id => @commentable.id,
                            :commentable_type => @commentable.class.to_s)
  end

  def create
    @commentable = find_commentable
    @comment = @commentable.comments.build(comment_params)
    @comment.user_id = current_user.id
    if @comment.save
      flash[:notice] = "Successfully created comment."
      redirect_to @commentable
    else
      flash[:error] = "Error adding comment."
    end
  end

  private
  def find_commentable
    params.each do |name, value|
      if name =~ /(.+)_id$/
        return $1.classify.constantize.find(value)
      end
    end
    nil
  end

  def comment_params
    params.require(:comment).permit(:body, :parent_id, :commentable_id, :commentable_type)
  end

end

app/controllers/lessons_controller.rb

class LessonsController < ApplicationController
  include Commentable
...
end

app/controllers/videos_controller.rb

class VideosController < ApplicationController
  include Commentable
...
end

Models

app/models/comment.rb

class Comment < ActiveRecord::Base
    has_ancestry
    belongs_to :user
    belongs_to :commentable, polymorphic: true
end

app/models/lesson.rb

class Lesson < ActiveRecord::Base
    has_many :comments, :as => :commentable, :dependent => :destroy
end

app/models/video.rb

class Video < ActiveRecord::Base
    has_many :comments, :as => :commentable, :dependent => :destroy
end

app/models/user.rb

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :comments, :as => :commentable, :dependent => :destroy
end

Helpers

app/helpers/comments_helper.rb

module CommentsHelper
  def nested_comments(comments)
    comments.map do |comment, sub_comments|
      content_tag(:div, render(comment), :class => "media media-nested")
    end.join.html_safe
  end
end

Lib

/lib/commentable.rb

require 'active_support/concern'

module Commentable
  extend ActiveSupport::Concern

  included do
    before_filter :comments, :only => [:show]
  end

  def comments
    @commentable = find_commentable
    @comments = @commentable.comments.arrange(:order => :created_at)
    @comment = Comment.new
  end

  private

  def find_commentable
    return params[:controller].singularize.classify.constantize.find(params[:id])
  end

end

Schema

create_table "comments", force: true do |t|
    t.text     "body"
    t.integer  "user_id"
    t.integer  "commentable_id"
    t.string   "commentable_type"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "ancestry"
  end

  add_index "comments", ["ancestry"], name: "index_comments_on_ancestry"

Views

Lessons & Views show.html.erb

<div class="tab-pane" id="comments">
  <%= nested_comments @comments %>
  <%= render "comments/form" %>
</div>

app/views/comments/_form.html.erb

<%= form_for [@commentable, @comment] do |f| %>
    <%= f.hidden_field :parent_id %>
    <p>
        <%= f.label :body, "New comment" %>
    </p>
    <%= f.text_area :body, :rows => 4 %>
    <p>
       <%= f.submit "Post Comment" %>
    </p>
<% end %>

app/views/comments/_comment.html.erb

<div class="media-body">
  <h4 class="media-heading"><%= comment.user.username %></h4>
  <i>
    <%= comment.created_at.strftime('%b %d, %Y at %H:%M')  %>
  </i>
  <p>
    <%= simple_format comment.body %>
  </p>
  <div class="actions">
    <%= link_to "Reply", new_polymorphic_path([@commentable, Comment.new], :parent_id => comment) %>
  </div>
  <%= nested_comments comment.children %>
</div>

Any feedback or ideas would be much appreciated. Thanks ;)

1

There are 1 best solutions below

0
On

Figured out a solution, however now child comments appear twice.

show.html.erb

<div class="tab-pane" id="comments">
    <%= nested_comments @lesson.comments %>
    <%= render "comments/form" %>
</div>