Reputation: 385
I have a simple blog app that reviews video games. Users can post comments on reviews.
My problem is that when I try to post a comment using AJAX(I'm a student trying to teach myself) on a review page, the page does a full refresh. The data is still submitted correctly, but then I have to reload the page in order to show the comments.
review.js
$(document).ready(function() {
$('#new_comment').on('submit', function(e) {
url = this.action
data = {
'authenticity_token': $("input[name='authenticity_token']").val(),
'comment': {
'content': $("#comment_content").val(),
'user_id': $("#comment_user_id").val()
}
};
$.ajax({
type: "POST",
url: url,
data: data,
success: function(response) {
$('#comments-section ol').append(response);
}
});
e.preventDefault();
});
});
comments_controller.rb #create action
def create
@review = Review.find_by(params[:id])
@comment = @review.comments.new(comment_params)
if !current_user
redirect_to review_oath(@review), alert: "You must be logged in to add a comment"
else
@comment.save
redirect_to @review
end
end
private
def comment_params
params.require(:comment).permit(:content, :user_id)
end
review.show.html.erb
<div id="comments-section">
<% if @review.comments.any? %>
<p>
<div><br>
<br>
<ul>
<% @review.comments.all.each do |c| %>
<h4 class="media-heading"><%= c.user.email %> said</h4> <br><li><p><%= c.content %></p></li>
<% end %>
</ul>
</p>
<% end %>
</div>
</div>
The full repo is here, make sure you're on the AJAX/JQUERY branch: https://github.com/jchu4483/Rails-Assessment-/tree/ajax/jquery
Thanks, and any help is much appreciated.
Upvotes: 0
Views: 1464
Reputation: 411
First of all, in order to ensure the app security, I suggest you to move the authentication method to a before_action in ApplicationController and skip it for the public actions.
If you are using devise gem you can add:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
end
Using this your app is secure by default.
For the comment update I recommend you to follow this approach:
Make your comment creation form an AJAX form adding the remote param and move it to a partial:
_form.html.erb
<%= form_for comment, remote: true do |form|%>
<%=form.hidden_field :review_id, review_id%>
<%=form.text_field :content%>
<%=form.submit :save%>
<% end %>
Create comments list partial too:
_comments.html.erb
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% comments.each do |comment| %>
<tr>
<td>
<%= image_tag comment.user.avatar.url %>
</td>
<td>
<%= comment.content %>
</td>
</tr>
<% end %>
</tbody>
</table>
So your review page should be something like this:
reviews/show.html.erb
<div class="review-photo">
<%= @review.photo %>
</div>
<div class="review-content">
<%= @review.content %>
</div>
<section class="comments">
<div class="new-comment-container">
<%= render 'my_new_comment_form_path', comment: Comment.new, review_id: @review.id %>
</div>
<div class="comments-container">
<%= render 'my_comments_partial_path', comments: @review.comments %>
</div>
</section>
Update your comments controller in order to response to AJAX on the create action:
def create
format.js do
@review = Review.find_by(params[:review_id])
@review.comments << Comment.create(comment_params)
end
end
private
def comment_params
params
.require(:comment)
.permit(:content)
.merge(user_id: current_user.id)
end
This code has a little refactor to ensure the commenter is the current user.
Then you should create a create.js.erb file to response to the create action, in this file you should replace the old list and the old form with the new ones:
comments/create.js.erb
$('.new-comment-container').html("<%= j render 'my_new_comment_form_path', comment: Comment.new, review_id: @review.id%>")
$('.comments-container').html("<%= j render 'my_comments_partial_path', comments: @review.comments%>")
I think this is a clean way to work with AJAX forms in rails.
Upvotes: 2