I have a rails app, in which my Posts model has Comments and the comments are votable. I'm using acts_as_votable.
I currently have the voting on the comments working. Now I'm trying to implement some javascript so that the page does not have to refresh every time someone votes on a comment, so that the vote goes through.
Here is what I had before(which was working):
In my comments controller:
def upvote_post_comment
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.liked_by current_user
respond_to do |format|
format.html {redirect_to :back}
end
end
And in my view:
<% if user_signed_in? && current_user != comment.user && !(current_user.voted_for? comment) %>
<%= link_to image_tag(‘vote.png'), like_post_comment_path(#post, comment), method: :put %> <a>
<%= "#{comment.votes.size}"%></a>
<% elsif user_signed_in? && (current_user = comment.user) %>
<%= image_tag(‘voted.png')%><a><%= "#{comment.votes.size}"%></a>
<% else %>
<%= image_tag(‘voted.png')%><a><%= "#{comment.votes.size}"%></a>
<% end %>
And this is what I now have:
In my comments controller:
def upvote_post_comment
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.liked_by current_user
respond_to do |format|
format.html {redirect_to :back }
format.json { render json: { count: #comment.liked_count } }
end
end
And in my view:
<% if user_signed_in? && current_user != comment.user && !(current_user.voted_for? comment) %>
<%= link_to image_tag(‘vote.png'), like_post_comment_path(#post, comment), method: :put, class: 'vote', remote: true %>
<a><%= "#{comment.votes.size}"%></a>
<script>
$('.vote')
.on('ajax:send', function () { $(this).addClass('loading'); })
.on('ajax:complete', function () { $(this).removeClass('loading'); })
.on('ajax:error', function () { $(this).after('<div class="error">There was an issue.</div>'); })
.on('ajax:success', function (data) { $(this).html(data.count); });
</script>
<% elsif user_signed_in? && (current_user = comment.user) %>
<%= image_tag(‘voted.png')%><a><%= "#{comment.votes.size}"%></a>
<% else %>
<%= image_tag(‘voted.png')%><a><%= "#{comment.votes.size}"%></a>
<% end %>
This shows me the error message: "There was an issue"
And when I refresh the page, I see that the vote went through and I see this in my terminal:
Started PUT “/1/comments/1/like" for 127.0.0.1 at 2014-04-06 18:54:38 -0400
Processing by CommentsController#upvote_post_comment as JS
Parameters: {"post_id"=>”1”, "id"=>”1”}
How do I get the voting to work via Javascript? So that the vote goes through, the vote count updates and the vote icon updates to voted.png instead of vote.png?
Your log says the request is formatted as JS.
Processing by CommentsController#upvote_post_comment as JS
Add data: { type: :json } to the link_to method to request a JSON format like so,
<%= link_to image_tag('vote.png'), like_post_comment_path(#post, comment), method: :put, class: 'vote', remote: true, data: { type: :json } %>
This will tell the controller you want a JSON response not a Javascript response.
Edit - updates from the comments.
Update controller to use,
format.json { render json: { count: #comment.likes.size } }
Update JS to use,
.on('ajax:success', function(e, data, status, xhr) { $(this).html(data.count); });
Related
There is some problem with using ajax in rails. I want to create new post in my wellcome/inex page. But when I push the botton it show
No route matches [POST] "/welcome/index"
wellcome/index.html
<b>Projects</b>
<ul id="projects">
<% #projects.each do |project| %>
<h2><%= project.title %></h2>
<% end %>
</ul>
<br>
<%= form_for :project do |f| %>
<%= f.text_field :title, :placeholder => ' Enter new project here..' %>
<but><%= f.submit 'Add Project'%></but>
<% end %>
welcome_controller.rb
class WelcomeController < ApplicationController
def index
#projects = Project.all
#project = Project.new
end
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'project was successfully created.' }
format.js
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
def project_params
params.require(:project).permit(:title)
end
end
create.js.erb
$('#projects').html("<%= escape_javascript (render 'projects') %>");
routes project
Prefix Verb URI Pattern Controller#Action
project_index GET /project(.:format) project#index
POST /project(.:format) project#create
new_project GET /project/new(.:format) project#new
edit_project GET /project/:id/edit(.:format) project#edit
project GET /project/:id(.:format) project#show
PATCH /project/:id(.:format) project#update
PUT /project/:id(.:format) project#update
DELETE /project/:id(.:format) project#destroy
Spent a lot of time updating this with AJAX but failed everytime. Any there to help? Thanks in advance
You have to add remote: true into form.
<%= form_for #project, url: project_index_path, remote: true do |f| %>
<%= f.text_field :title, :placeholder => ' Enter new project here..' %>
<but><%= f.submit 'Add Project'%></but>
<% end %>
If you want integrate Ajax and Ruby you need to add the line below inside your link action
remote:true
also you can check this about Ajax and Ruby
How Ajax works with ruby on rails
server log:
`ActionController::ParameterMissing (param is missing or the value is empty: comment)`
used pry gem gem params:
<ActionController::Parameters {"utf8"=>"✓", "comment_name"=>"123432",
"comment_description"=>"231424", "commit"=>"submit",
"controller"=>"comments", "action"=>"create", "article_id"=>"5"} permitted: false>
I know the :comment should wrapper coment_name and comment_description
so on validate add submitHandler try fix the format error
click submit button the browser show:
jquery validate:
$(function () {
$("form#new_comment").validate({
rules: {
comment_name: {
required: true,
minlength: 3
},
comment_description: {
required: true,
minlength: 5
},
submitHandler: function (form) {
$.ajax({
url: form.action,
type: form.method,
data: $(form).serializeArray(),
dataType: 'script'
});
}
}
});
});
_form.html.erb:
<%= simple_form_for [#article, #article.comments.build], remote: true do |f| %>
<%= f.input :name, input_html: { name: "comment_name"} %>
<%= f.input :description, input_html: { name: "comment_description" } %>
<%= f.submit :submit, class: "btn btn-default" %>
<% end %>
comment_controller:
class CommentsController < ApplicationController
before_action :get_article
before_action :authenticate_user!
def create
#comment = #article.comments.create(comment_params)
#comment.user_id = current_user.id
if #comment.save
respond_to do |format|
format.html { redirect_to #article, notice: "creaed succeed"}
format.js { }
end
else
redirect_to #article, notice: "characters is too short or name has been taken"
end
end
def destroy
#comment = #article.comments.find(params[:id])
if #comment.destroy
respond_to do |format|
format.html { redirect_to #article }
format.js { }
end
end
end
private
def comment_params
params.require(:comment).permit(:name, :description, :article_id, :user_id)
end
def get_article
#article = Article.find(params[:article_id])
end
end
any help thank 🙃
The controller expects
<ActionController::Parameters {"utf8"=>"✓", "comment"=>
{name"=>"123432","description"=>"231424"}, "commit"=>"submit",
"controller"=>"comments", "action"=>"create", "article_id"=>"5"}
permitted: false>
In your form, by declaring "name" attributes for the 'name' and 'description' fields, you are essentially overwriting the "name" field's name from comment[name] to comment_name. So just remove those name attributes from your form
<%= simple_form_for [#article, #article.comments.build], remote: true do |f| %>
<%= f.input :name%>
<%= f.input :description%>
<%= f.submit :submit, class: "btn btn-default" %>
<% end %>`
I am trying to use JavaScript with jquery in rails to update a div without reloading the page. Its working but the comment is being created twice. I know something is wrong in the form partial but couldn't figure it out. Any help?
The following are the files -
_new_comment.html.erb
<%= form_for [:home, Comment.new], :url => home_comments_path, :html => {:id => "comment-new-" + post.id.to_s} do |f| %>
<div>
<%= f.text_area :message, :class => "message-area-" + post.id.to_s, :placeholder => "Add comment..." %>
<%= f.hidden_field :post_id, :value => post.id %>
<span class="new-comment"><%= link_to 'Add', '#', remote: true, :onclick => "$('#comment-new-#{post.id}').submit()" %></span>
</div>
<% end %>
comments_controller.rb
def create
#comment = Comment.new(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:notice] = 'Comment added sucessfully'
respond_to do |format|
format.html { redirect_to home_posts_url }
format.js
end
end
end
create.js.erb
$("#comment-new-83").before('<div class="notice"><%= escape_javascript(flash[:notice]) %></div>');
$("#comment-new-83")[0].reset();
home.js
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
$(document).ready(function() {
$("#comment-new-83").submit(function() {
$.post($(this).attr("action"), $(this).serialize(), null, "script");
return false;
})
})
form_for will automatically post to the controller. You need not submit the form explicitly using jquery.
Reference
I'm following the jquery file upload video from RailsCast but I can't get the images to show up without refreshing the page.
My photo is being uploaded through this form:
<%= simple_form_for #upload, html: { multipart: true, id: 'add_new_project_photos' } do |f| %>
<%= f.simple_fields_for :project_images, ProjectImage.new, child_index: ProjectImage.new.object_id do |ff| %>
<%= ff.file_field :photo, multiple: true, name: "project[project_images_attributes][][photo]" %>
<% end %>
<% end %>
I also created a create.js.erb file.
<% if #project.project_images.new_record? %>
alert("Failed to upload painting: <%= j #painting.errors.full_messages.join', ').html_safe %>");
<% else %>
$("#added_photos").append("<%= j render(#project) %>");
<% end %>
My controller
class ProjectsController < ApplicationController
#... other methods
def create
#project = Project.new(trip_params)
#upload = Project.create(trip_params)
if request.xhr?
redirect_to root_url
else
redirect_to :back
end
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
end
My coffee script file
jQuery ->
$('#add_new_trip_photos').fileupload
dataType: "script"
You need to respond to js as well. In your create method you are only responding to html and json
format.js
Should be placed inside your respond_to block
I am following section 4 (Server Side Concerns) to set up ajax on a page. I've copied the tutorial text completely (replacing the model names with my own) and it creates and saves my "Participants" record and refreshes the partial....but it posts this weird code below the just submitted form:
$("
\n\n Helper:sampleemail#sample.com \n<\/li>\n\n").appendTo("#participants");
This seems to be some sort of weird mash-up of my partial information and my creat.js. It's not really an error...just extra code.
Here's my code
class ParticipantsController < ApplicationController
def new
#participant = Participant.new
#participants = #participants.recently_updated
end
def create
#participant = Participant.new(participant_params)
respond_to do |format|
if #participant.save
format.html { redirect_to #participant, notice: 'Helper Invited!' }
format.js {}
format.json { render json: #participant, status: :created, location: #participant }
else
format.html { render action: "new" }
format.json { render json: #participant.errors, status: :unprocessable_entity }
end
end
end
_form.html.erb
<ul id="participants">
<%= render #participants %>
</ul>
<%= form_for(#participant, remote: true) do |f| %>
<%= f.label :email %><br>
<%= f.email_field :email %>
<%= f.submit 'SUBMIT' %>
<script>
$(document).ready(function() {
return $("#new_participant").on("ajax:success", function(e, data, status, xhr) {
return $("#new_participant").append(xhr.responseText);
}).on("ajax:error", function(e, xhr, status, error) {
return $("#new_participant").append("<p>Oops. Please Try again.</p>");
});
});
</script>
<script>
$(function() {
return $("a[data-remote]").on("ajax:success", function(e, data, status, xhr) {
return alert("The helper has been removed and notified.");
});
});
</script>
_participant.html.erb
<li >
<%= participant.email %> <%= link_to participant, remote: true, method: :delete, data: { confirm: 'Are you sure?' } do %>REMOVE<% end %>
</li>
create.js.erb
$("<%= escape_javascript(render #participant) %>").appendTo("#participants");
destroy.js.erb
$('#participants').html("<%= j (render #participants) %>");
It seems like you are both responding with a js.erb file and listening for the ajax:success event. You should only need to do one. Right now the ajax:success listener is appending the response to the form and the response is javascript code. Remove that listener and you should get the desired results.