2

In my Rails app users can leave comments on posts. When a user submits their comment this code is run from the CommentsController:

def create
    @comment = Comment.new(comment_params)
    @comment.user_id = current_user.id
    @matchup = Post.find(comment_params[:post_id])
    if @comment.save  
      respond_to do |format|
        format.js
      end
    end
end

I have it set up so when a comment is created I run this bit of code in comments/create.js.erb

$("#comment-form-<%= @post.id %>").replaceWith("<%= j render partial: 'comments/comment_form', locals: {post: @post} %>"),
$("#new-comment-<%= @post.id %>").replaceWith("<%= j render partial: 'comments/comment', locals: {post: @post, comment: @comment} %>");

This re-renders the comment form and renders the user's new comment at the top of the comment list. It works perfectly for the first comment.

However, if the user does not refresh the page and leaves a second comment, this code does not work. The second comment is created but only appears if the page is refreshed. I'm very new when it comes to JS. What am I missing?

Phil Mok
  • 3,860
  • 6
  • 24
  • 36
  • Have you considered using rails to handle the create method, and AJAX to refresh the page? – Matt C Apr 17 '16 at 01:03
  • @MatthewCliatt the create method is handled in the CommentsController. I'll add that to the question. – Phil Mok Apr 17 '16 at 01:05
  • What does create.js do? – Matt C Apr 17 '16 at 01:06
  • @MatthewCliatt create.js.erb contains those two lines of code that are in the question. The first line re-renders the comment form and the second renders the user's new comment at the top of the comment list. – Phil Mok Apr 17 '16 at 01:07
  • If you aren't set on using JavaScript to add in the comments, then I have a way you can do it with Rails. – Matt C Apr 17 '16 at 01:08
  • @MatthewCliatt I'm open to exploring all options as long as users can comment as many times as they want without refreshing the page. – Phil Mok Apr 17 '16 at 01:17
  • I posted my answer which goes over a few things to make sure are set up correctly, but I'll continue to troubleshoot with you. Does your form/link to create a comment have `remote: true`? – Matt C Apr 17 '16 at 01:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109355/discussion-between-plmok61-and-matthew-cliatt). – Phil Mok Apr 17 '16 at 02:22

2 Answers2

1

When a new comment created, you don't need to replace the original comments dom, you may need to append/preppend or before/after the new comment to it. Try change:

$("#new-comment-<%= @post.id %>").replaceWith("<%= j render partial: 'comments/comment', locals: {post: @post, comment: @comment} %>"

To:

 $("#new-comment-<%= @post.id %>").before("<%= j render partial: 'comments/comment', locals: {post: @post, comment: @comment} %>"
lei liu
  • 2,735
  • 1
  • 16
  • 18
1

EDIT - Troubleshoot first

I was thinking that your code looks fine and should work, unless you are missing some from below. So just troubleshoot two things to make sure the issue isn't something trivial.

If your JavaScript code that updates the view is inside of a function, make sure that format.js calls that function not just the JavaScript file.

Like this:

respond_to do |format|
  format.js { render :js => "my_function();" }
end

Check out this post for a more detailed example.

You also might want to have a look at these posts from people who had the same problem as you, since it should be very simple to see if you had the same issue as them:

Post 1

Post 2

Post 3

If the above troubleshooting didn't work, then have a look below.


You probably want to use AJAX if you want to actually have things happen on the back end (store a comment in the DB), and show those changes on the front end (show new comments), without a page refresh.

With Rails, AJAX is dead simple. The process of using AJAX with your Rails app so that the page doesn't have to be reloaded/refreshed has been explained and outlined in many resources. The best resource I've found, is this guide.

Since there are dead simple guides that are really good at explaining the process, I won't go into too much detail here.


It looks like you're pretty much setup for AJAX, just make sure you have everything included that I list below.

You must add remote: true (or for earlier versions :remote => true), to your links/buttons. This will allow the AJAX call to take place. Like this example:

<%= link_to 'Post Comment!', create_comments_path('params in here'), :remote => true %>

Or maybe if you're using a form, you can simply add the remote part to the submit tag:

<%= form_for [@post, Comment.new], remote: true do |f| %>

Of course your exact line might differ some, based on your controllers and views.

The next step is to add a respond_to..format.js.. block to your method which handles creating the comment in the DB, or whatever else you may be doing. I didn't list out the entire block since you've already got that in your code :)

Do be sure that no controller methods that get called have a format.html line that has a body in the respond_to.. block. format.html is fine, but format.html { #anything in here } is not fine.

Next, we need to use make the .js file which will repopulate the view with the newly created comments (or whatever else). It looks like you've already got this file already made, so I won't talk about how to make it.


If you have any trouble, you will get the most help from these guides:

Community
  • 1
  • 1
Matt C
  • 4,470
  • 5
  • 26
  • 44
  • Thanks for all the info. I will study these guides and put them to good use! – Phil Mok Apr 17 '16 at 02:04
  • @plmok61 Great. I've added a troubleshooting section to the top of my answer. I think it will help you quite a bit. Let me know if what I've posted fixes your problem. – Matt C Apr 17 '16 at 02:18