Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

Rails ajax append single item from collection

In my app I have a commenting system in place that displays comments as a collection and I've got ajax commenting working but currently it renders the entire collection again but what I want is to just append the latest comment. Here's my code:

comments_controller.rb

class CommentsController < ApplicationController

before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member

def index
   redirect_to root_path
end

def new
    @comment = @commentable.comments.new
end

def create
    @comment = @commentable.comments.new(params[:comment])
    @comment.member = current_member
    respond_to do |format|
        if @comment.save
          format.html { redirect_to :back }
          format.json
          format.js
        else
          format.html { redirect_to :back }
          format.json
          format.js
        end
    end 
end

def destroy
    @comment = Comment.find(params[:id])
    respond_to do |format|
        if @comment.member == current_member || @commentable.member == current_member
          @comment.destroy
          format.html { redirect_to :back }
        else
          format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
        end
    end 
end

private

def load_commentable
    klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
    @commentable = klass.find(params["#{klass.name.underscore}_id"])
end

def find_member
    @member = Member.find_by_user_name(params[:user_name])
end 

end

statuses_controller

def show
    @status = Status.find(params[:id])
    @commentable = @status
    @comments = @commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
    @comment = Comment.new
    respond_to do |format|
      format.html # show.html.erb
      format.json { redirect_to profile_path(current_member) }
      format.js
    end
end

statuses/show.html.erb

<% if member_signed_in? %>
    <div id="comm_form_wrap">
        <%= render "shared/comment_form" %>
    </div>

    <div id="comments_<%= @commentable.id %>">
        <%= render partial: "shared/comments", :collection => @comments, :as => :comment %>
    </div>
<% end %>

shared/_comments.html.erb

<div id="comment_<%= comment.commentable.id %>_<%= comment.id %>" class="comments">
    <span class="comment_av">
        <%= comment_avatar_link_2 comment.member, :class => "com_av", title: comment.member.full_name, alt: comment.member.full_name %>
    </span>
    <span>

        <div class="comment_name">
            <% if comment.member == @commentable.member %>
                <%= link_to comment.member.user_name, profile_path(comment.member) %> <span class="owner">Creator</span>
            <% else %>
                <%= link_to comment.member.user_name, profile_path(comment.member) %>
            <% end %>

            <% if comment.member == current_member || @commentable.member == current_member %>
                <span class="comment_del">
                    <%= link_to image_tag("Delete.png", title: 'Delete'), [@commentable, comment], remote: true, method: :delete, data: { confirm: 'Are you sure?' } %>
                </span>
            <% end %>
            <span class="meta">
                <%= time_ago_in_words(comment.created_at) %>
            </span>
        </div>

        <div class="com_con">
            <%= Rinku.auto_link(comment.content).html_safe %>
        </div>
    </span>
</div>

comments/create.js.erb

$("#comments_<%= @commentable.id %>").html("<%= escape_javascript(render :partial => 'shared/comments', :collection => @comments, :as => :comment) %>");
$('#comment_form')[0].reset();

If I just change html to append in the create.js.erb file it will append the entire collection of comments. I guess I could copy and paste the code from my comments partial but that'd be a lot of code and I wouldn't know how to define the variables that way. What's the best way for me to append the single new comment? Thanks in advance.

2 Answers

You just need to render one but you say render a collection. Instead render @comment, not @comments.

comments/create.js.erb

$("#comments_<%= @commentable.id %>").append("<%= escape_javascript(render partial: 'shared/comments', object: @comment) %>");

Thanks

I was able to figure this one out. Instead of rendering or appending the collection I could just append @comment like so:

$("#comments_<%= @commentable.id %>").append("<%= escape_javascript(render :partial => @comment, :locals => {:comment => @comment}) %>");

Then I just needed to create a _comment.html.erb partial in my comments folder.