I'm trying to offer my users a link to click which will: (1) trigger an AJAX call, (2) activate a controller/action which will destroy a Comment object, (3) have that same controller/action respond back with both HTML and JavaScript.
Everything works fine, except the JavaScript response. For some reason, Rails cannot find the .js.erb template that corresponds to my controller/action, so it doesn't fire any client-side JavaScript, and instead throws a "No template found" warning.
View that contains the clickable link:
<%= link_to blog_post_comment_path(#blog_post,c), method: :delete, :remote => true do %>
<%= fa_icon "trash" %>
<% end %>
Controller:
class CommentsController < ApplicationController
def destroy
#blog_post = BlogPost.find(params[:blog_post_id])
#comment = Comment.find(params[:id])
#comment.delete
respond_to do |format|
format.html { redirect_to edit_blog_post_path(#blog_post), notice: "Comment deleted!" }
format.js
end
end
end
I have a view that lives at: /app/views/comments/destroy.js.erb. No matter what JavaScript I add to this file, it won't execute.
When I click the link_to link in a browser, the Rails logs shows:
Comment Destroy (1.5ms) DELETE FROM "comments" WHERE "comments"."id" = ? [["id", 44]]
↳ app/controllers/comments_controller.rb:7
No template found for CommentsController#destroy, rendering head :no_content
Related
I have to ask about something that probably no one uses anymore. I want to display flash[:notice] after successfully AJAX action. I'm aware of this and that one and even this gist but none of them fit my example:
#controller code
def new
#registrant = Registrant.new
respond_to do |format|
format.html
if params[:add_patient_to_caregiver]
format.js { render partial: 'add_patient_to_caregiver' }
end
end
end
#view triggered controller#new action via AJAX
<%= link_to 'Add Patient to Caregiver', patient_to_caregiver_path(add_patient_to_caregiver: true, patient_to_caregiver: registrant.id), method: :get, remote: true %>
I want to have something like format.js { render partial: 'add_patient_to_caregiver', flash[:notice] = 'Patient Added' } to display it in a view. I've come up with a workaround:
_add_patient_to_caregiver.js.erb
$("#add-patient").html("<%= escape_javascript(render :partial => 'registrants/add_patient') %>");
$("#flash-messages").after("<div class='alert alert-success'> Patient Added </div>");
And flash message shows up but there are no close button there. Is there any better way to do so? or how to add close button to that message so that the whole page doesn't reload when it is pressed?
So I've started getting this error after I tried to implement AJAX comments in my rails app:
ActionController::InvalidAuthenticityToken in CommentsController#create
ActionController::InvalidAuthenticityToken
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
end
end
Here are all the codes from the relevant files:
comments_controller.rb
class CommentsController < ApplicationController
before_action :find_post
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
else
flash[:alert] = "Check the comment form, something went horribly wrong."
render root_path
end
end
Add comments form:
= form_for([post, post.comments.build], remote: true) do |f|
= f.text_field :content, placeholder: 'Add a comment...', class: "comment_content", id: "comment_content_#{post.id}"
views/comments/create.js.erb
$('#comments_<%= #post.id %>').append("<%=j render 'comments/comment', post: #post, comment: #comment %>");
$('#comment_content_<%= #post.id %>').val('')
comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
I have no idea what's causing this error as it worked fine before the introduction of AJAX. I looked up answers to similar problems on stackoverflow and added protect_from_forgery at the top of comments_controller.rb to no avail. I don't get the InvalidAuthenticityToken error alright, but instead, it gives me a different error:
NoMethodError in CommentsController#create
undefined method `id' for nil:NilClass
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id #highlighted line
if #comment.save
respond_to do |format|
Solution to my problem was to put on first line inside controller:
skip_before_action :verify_authenticity_token, :only => [:create,:inquire_enterprise]
As you can see I am escaping 2 actions which produced the error.
You have to send an authenticity token with your forms, it should be generated in your form_for, so I guess your ajax is just not sending it.
In case it's not automatically generated, you can do it manually: <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Unless config.action_view.embed_authenticity_token_in_remote_forms is set to true (the default is false), Rails won't generate the hidden input containing the csrf token if the form is a remote one.
This is because ajax powered forms have another mechanism for getting the token & this change means you can now fragment cache html containing this form because it no longer contains content that changes for every user.
This mechanism is adding the csrf tag to the page's meta tags, which the rails javascript can read and add to the ajax request. There is a helper, csrf_meta_tags that does this for you - just add a call to it in the <head> of the html you are rendering (this will usually be in your layout file).
Using rails 4 and ruby 2
Having trouble displaying the flash messages from my controllers. My method looks like this:
def create
#salary_report = SalaryReport.create(salary_report_params)
if #salary_report.save
redirect_to #salary_report
flash[:notice] = "Lönerapporten sparades korrekt!"
puts "salary report saved #{flash[:notice]}"
else
render :new, notice: "Något gick fel när lönerapporten skulle sparas!"
end
end
As you can see, I have added a puts statement printing out the flash notice just to prove that the flash notice is getting generated after the redirect.
The logs look like this after creating a salary report:
Redirected to http://localhost:3000/salary_reports/20
salary report saved Lönerapporten sparades korrekt!
Completed 302 Found in 25ms (ActiveRecord: 9.7ms)
After getting to show view logs:
Started GET "/salary_reports/22" for 127.0.0.1 at 2013-07-24 16:08:42 +0200
Processing by SalaryReportController#show as HTML
Parameters: {"id"=>"22"}
SalaryReport Load (0.5ms) SELECT "salary_reports".* FROM "salary_reports" WHERE "salary_reports"."id" = ? LIMIT 1 [["id", "22"]]
Document Lo ad (0.3ms) SELECT "documents".* FROM "documents" WHERE "documents"."salary_report_id" = ? [["salary_report_id", 22]]
Rendered salary_report/show.html.erb within layouts/application (6.1ms)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
Completed 200 OK in 62ms (Views: 58.0ms | ActiveRecord: 1.1ms)
In the view, I show the messages with this:
<% flash.each do |name, msg| %>
<% if msg.is_a?(String) %>
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert">×</a>
<%= content_tag :div, msg, :id => "flash_#{name}" %>
</div>
<% end %>
<% end %>
I have tried a variety of different ways to write the controller method but nothing seems to help. Very uncertain about what the problem could be.
You are setting your flash[:notice] after redirect. Try switching the order of those calls i.e. set the flash message first then redirect second:
def create
#salary_report = SalaryReport.create(salary_report_params)
if #salary_report.save
flash[:notice] = "Lönerapporten sparades korrekt!"
puts "salary report saved #{flash[:notice]}"
redirect_to #salary_report
else
render :new, notice: "Något gick fel när lönerapporten skulle sparas!"
end
end
Try defining flash message in a redirect clause:
def create
#salary_report = SalaryReport.create(salary_report_params)
if #salary_report.save
redirect_to #salary_report, notice: "Lönerapporten sparades korrekt!"
else
render :new, notice: "Något gick fel när lönerapporten skulle sparas!"
end
end
try use flash.keep.
Anything you place in the flash will be exposed to the very next action and then cleared out.
In this case flash pass into 2 actions, another controller and a view.
def create
#salary_report = SalaryReport.create(salary_report_params)
if #salary_report.save
flash.keep[:notice] = "Lönerapporten sparades korrekt!"
puts "salary report saved #{flash[:notice]}"
redirect_to #salary_report
else
render :new, notice: "Något gick fel när lönerapporten skulle sparas!"
end
end
First off, instead of defining the flash message separately, put it inline with your redirect, just like you're doing with your render line below. This is more of a style change than anything majorly functional:
def create
#salary_report = SalaryReport.create(salary_report_params)
if #salary_report.save
redirect_to #salary_report, notice: "Lönerapporten sparades korrekt!"
else
render :new, notice: "Något gick fel när lönerapporten skulle sparas!"
end
end
As for the reason why it is not displaying, this is most likely an issue with your flash message view code. This is because, as you have tested, the flash hash is being set properly, it's just not being displayed.
Try temporarily replacing your flash message code with the following simpler version.
Ensure it's in your application.html.erb near the top, but that's again just styling:
<% flash.each do |name, msg| %>
<%= content_tag :p, msg if msg.is_a?(String) %>
<% end %>
I've got pretty the same problem due to devise gem and I found a solution with the cookies.
You have to set a cookie with a value before redirecting, and then the controller tests if there is a cookie. If yes, it tests what is its value and display the flash message.
Take a look right there for a complete explanation :
flash[:notice] not working with the after_sign_out_path_for - (devise)
Hope it can help you.
I recently started with Rails 3.2 and am stuck while trying to implement some ajax functionality in my app. I followed this railscast completely (http://railscasts.com/episodes/240-search-sort-paginate-with-ajax). Beyond this I want to implement a shortlist button for each product which lets user shortlist products and store them in the session. I also want a small list of shortlisted products to show up on the same page, which needs to be ajax updated.
I am wondering what is the best way to do that. I currently implemented the link_to buttons with remote tag and a helper function to change the link to shortlist/unshortlist. I also, used a conditional div to show the shortlist based on the length of shortlist. However, the issue is that whenever I shortlist, the order of the products table is also reset.
Here are snippets of my code :-
Application_helper.rb
def shortlist_unshortlist_link(product_id )
if (user_session.already_shortlisted? product_id )
link_to 'Unshortlist', { action: 'unshortlist', id: product_id }, remote => 'true'
else
link_to 'Shortlist', { action: 'shortlist', id: product_id }, remote => 'true'
end
end
def shortlist_div
shortlist=user_session.shortlist
if (user_session.shortlist.length > 0)
render :partial => 'pages/shortlist_fields'
end
end
products/index.html.erb
<div id="product">
<% #products.each do |product| %>
<tr>....
<td><%= shortlist_unshortlist_link(product.id.to_s) %></td>
</table>
</div>
<div class="shortlist"><%= shortlist_div() %> </div>
products_controller.rb
def shortlist
user_session.add_to_shortlist(params[:id])
redirect_to products_path
end
def unshortlist
user_session.remove_from_shortlist(params[:id])
redirect_to products_path
end
I think, the issue is because of redirect_to, but I am not getting how to avoid this without hurting the functionality. Am I on a totally wrong path here. Is this a good way to implement this. Any suggestions.
thanks,
Amit
you should use in shortlist method,
respond_to do |format|
format.html {redirect_to products_path }#shortlist.html.erb
format.js #shortlist.js.erb
end
and write your java script to #shortlist.js.erb file.
Do the same with unshortlist.
I agree with Sush, you didn't response to the ajax request from link_to.
In your controller, shortlist method, response to the ajax request
respond_to do |format|
format.html {redirect_to products_path }
format.js
end
By convention in Rails, format.js will execute the js.erb file with the same name as your method.
And in the shortlist.js.erb, you may write something like:
$('#shortlist').html('<%= escape_javascript(render "pages/shortlist_fields")%>');
Besides, you can also call the same js.erb file.
In the unshortlist method, you can do it like that:
respond_to do |format|
format.html {redirect_to products_path }
format.js {render :action=>'shortlist'}
end
I'm wanting to add some AJAX functionality to my Rails app, but have no idea where to start.
Here is the method that adds an item to an order:
def add_item_to_order
if session[:order_id].nil?
#order = Order.new #Don't create an order until there is an item to be added to it.
#order.account_id = session[:user_id]
else
#order = Order.find(session[:order_id])
end
item = Item.find(params[:id])
o_item = OrderItem.new
o_item.item_id = item.id
#order.order_items << o_item
#order.total += item.sale_price
#order.save
session[:order_id] = #order.id
redirect_to order_home_path
end
This is run when the user clicks:
<%= link_to item.name, add_item_to_order_path(item.id), :class => "fixed medium green button"%>
Can anyone give me any tips on how to get started, so the the item is added to the order via AJAX?
Check on how to render javascript. In normal requests one would redirect to some action or render some view etc, for a XHR (XmlHttpRequest) you can render javascript through a server-sided js template that would be rendered. You will have to use the LegacyPrototypeHelpers provided for Rails-3 as the original helpers were only officially available for Rails-2.
A better approach(unobtrusive as Rails 3 prefers) will be to just send some data from the server. In the following example you have above I guess if you send item.id via a JSON object or some other format and then read it in the success callback of the place from where you made the XMLHttpRequest, then after getting the item.id you could create the HTML that the link_to creates and then append it to the DOM.
Great tutorial, did this myself: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book Chapter 12 has some stuff on Ajax.
Important part is to set your link_to paramater data-remote to true:
<%= link_to item.name, add_item_to_order_path(item.id),
:class => "fixed medium green button" data-remote="true" method="post"%>
and in your controller you add
def add_item_to_order
# other stuff
# at the bottom:
respond_to do |format|
format.html { redirect_to order_home_path }
format.js
end
end
Then you'll need a .js.erb file to handle the format.js repsonse:
$("your_form").update("<%= escape_javascript(render('partial_page')) %>")
and a partial page file to hold the new data..