Nested Comments with Ajax and Ancestry gem

745 Views Asked by At

I'm trying to build in comments into my Rails 4 app. I have been able to get nested comments to work using Railcasts 262 as a guide. I would like to make the new comment field appear when a user wants to reply to a comment or add a new one and limit the times the page reloads. I have viewed Railscasts 136 and others. I'm using the ancestry gem and can't get the form and comments to show as desired.

The problem seems to be that when I send the user to the new_comment_path, the post_id gets lost. I had been able to get it to save with the comment before adding the ajax and new step in the routes. Before I was just rendering the comment form on the post show page and it worked. Now the new comment is getting saved, but the post_id, ancestry_id and parent_id are all nil. I can therefore not render those comments to show up on the show page for the posts. After I get the new_comment to work I will also set it up so that the "reply" also works. Please let me know if you have any suggestions. Thanks.

post.rb

class Post < ActiveRecord::Base
    belongs_to :user
    has_many :comments

comment.rb

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
  has_ancestry
end

_comment_form.html.erb

<%= form_for @comment, remote: true do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="comment_field">
    <%= f.hidden_field :post_id, :value => @comment.post_id %>
    <%= f.hidden_field :parent_id, :value => params[:parent_id] %>
    <%= f.text_area :content, placeholder: "" %>
  </div>
  <button class="btn" type="submit">
    Send request
  </button>
<% end %>

post show.html.erb

... information about post ...
<div id="added_comments">
   <%= link_to "New Comment", new_comment_path, id: "new_link", remote: true, :post => @post %>
</div>
<%= nested_comments @post.comments.arrange(:order => :created_at)  %> 

comment new.html.erb

<h1>New Comment</h1>
<%= render 'comment/form' %>

comment new.js.erb

$('#new_link').hide().after('<%= j render("form") %>');

create.js.erb

$('#new_comment').remove();
$('#new_link').show();
$('#added_comments').append('<%= j nested_comments (@post.comments).arrange(:order => :created_at)  %>');

_comment.html.erb

<%= link_to comment.user.name, comment.user %>
<%= comment.content %>
<%= link_to "Reply", post_path(@post, :parent_id => comment) %>

comments_controller.rb

def new
  @comment = Comment.new(:parent_id => params[:parent_id], :post_id => params[:post_id])
end

def create
    @comment = Comment.create(comment_params)
    @comment.user = current_user
      if @comment.save
        CommentMailer.comment_confirmation(@comment).deliver
        flash[:success] = "Comment added."
        respond_to do |format|
          format.html { redirect_to :back }
          format.js
          end
      else
         flash[:error] = "Comment cannot be blank"
      end
end

def show
    @comment = Comment.find(params[:id])
    @user = @comment.user
end

posts_controller.rb

def show
  @post = Post.find(params[:id])
  @comment = @post.comments.build(:parent_id => params[:parent_id])
  @user = User.find(@post.user_id)
  @comment.user_id = current_user
end

def create
  @post = current_user.posts.build(post_params)
  if @post.save
    flash[:success] = "Post added!"
    redirect_to root_url
  else
    @repository_items = [ ]
    render 'shared/_post_form'
  end
end
1

There are 1 best solutions below

0
On

Your posts show template is a bit wrong. When you pass an arbitrary symbol to link_to it becomes an html attribute on the link tag so when you use

:post => @post 

In your html that becomes something like

post="#<Post:0x007fe26e0907d8>"

which won't work for you because you want to pass the parent_id and post_id as params to the new comment action. Instead you could try something like this

<%= link_to "New Comment", new_comment_path(parent_id: @post.id, post_id: @post.id), id: "new_link", remote: true %>

Then when you go to implement your comment reply you'd have something like

<%= @post.comments.each do |comment| %>
  <%= link_to "Reply to Comment", new_comment_path(parent_id: comment.id, post_id: @post.id), id: "new_link", remote: true %>
<%- end %>

Also, you might have just omitted files, but from what I see the comment new.js.erb template needs to reference comment_form instead of form since that's what you named your template