render_to_string breaks action rendering - ruby-on-rails

In my controller I want to render one of the HTML partials into a string variable, then send it with the Pusher and finalize the action with a regular rendering of the JS file (this is AJAX request).
I'm making an AJAX call and my action looks like this:
def create
#my_Object = ...
#html_content = escape_javascript(render_to_string :partial => 'my_partial', :object => #my_object )
Pusher.trigger(
'my-channel',
'my-event',
{ message: #html_content }
)
end
Given my understanding I would expect to see the "create.js" file being rendered at the end of this action, but this is not the case.
If in the "create.js" I put:
alert("test");
I do not see the dialog even though in rails logs I do see that the "create.js" partial is rendered.
When I remove the render_to_string part all works fine and the "create.js" gets properly rendered.
Can you help? What am I missing?

It seems that the fix is to explicitly call
respond_to do |format|
format.js
end
after the render_to_string.
This is strange as without the render_to_string call you do no thave to do that...

Related

Multiple render error in rails app while generating pdf file via wicked pdf

I'm using wicked PDF in my rails app to generate PDF. and that is done by a private function generate_pdf in my controler becase after the purchase process i want to generate that pdf and then mailer function to send that pdf to user.
error
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
code is something lie this.
def place_order
... some code
download_new_pdf(#pur)
UserMailer.confirm_order(#pur).deliver
format.html { redirect_to(:action=>'order_confirmed/'+#pur[:id].to_s) }
end
and the helper function will be
def download_new_pdf(id)
#my_ticket = Purchase.find(id)
#event = Event.find(#my_ticket[:event_id])
render :pdf => "#{#my_ticket[:random_no]}.pdf",
:template => 'tickets/download_invoice.html.erb',
:save_to_file => Rails.root.join('public/data/docs', "#{#my_ticket[:random_no]}.pdf")
end
place_order will do all the DB stuff and at the end generate pdf, send mail and redirect to conformation page. But here it's giving me multiple render error coz of
format.html { redirect_to(:action=>'order_confirmed/'+#pur[:id].to_s) }
and
render :pdf => "#{#my_ticket[:random_no]}.pdf",
:template => 'tickets/download_invoice.html.erb',
:save_to_file => Rails.root.join('public/data/docs', "#{#my_ticket[:random_no]}.pdf")
i tried putting and return but still no luck,Any help would be appreciated. Thanks !!!
Your error is simple. You are render in download_new_pdf and redirecting in place_orderat the same time. It looks like you need to create the pdf file and store in the file system, not to show it immediately to the user, so, check the readme, here is explained how to just create the PDF and don't render it to the client

Rails: action and views

My question is : do we need a view file for each action in our controller?
(like if we defined a say_hello action in a controller, is it necessary to add say_hello.html.erb in his view directory?
I'll edit this to say it depends (with same content). If you plan on using that controller action as JS or JSON you don't need a view file. if you want one to share in multiple views, the file can contain a shared partial (which can be used in other views). This examples is shown by the generators scaffolding create examples like this. They are helpful if you are learning rails. Not great otherwise.
If you were to share a partial, you could have a partial named _form.html.erb and then inside your say_hello.html.erb file, it would just call:
<%= render 'form' %>
If you want to render JSON or JS files you can respond_to in your action:
respond_to do |format|
format.html # say_hello.html.erb
format.json { render json: #hello } #no file needed
format.js { render js: #hello }
#format.js   {} #do nothing... or use a little javascript in there...
# or have a file named say_hello.js.erb and use your #hello variable
end
Edit:
One last update. Your say_hello.js.erb file can do the anything on another view (if called remotely):
say_hello.js.erb
<% if #hello.attribute == "some value" %>
$('#div_in_another_view').show();
<% else %>
$('#div_in_somewhere_else').hide();
<% end %>
You can do jQuery and anything you want to the view calling it (as long as it's using AJAX).
End edit
Guides are great place to get started. Railscasts.com as well (even though Ryan isn't updating anymore).
Edit: A great example on the different options on the respond_to is on this rails guide regarding javascript
You can just pass javascript straight from that format.js call, or use a file if you need more complicated stuff. You don't need to do anything also. You could just have it return xml or nothing as well, depending on your use case.
No, it is not required. For example, you can render json or xml data from the controller without needed a view at all. This article explains it very well http://guides.rubyonrails.org/layouts_and_rendering.html
No you do not need a view for each action. BUT you do need a view for each action that will reach the end of the method.
If you return anywhere in the action then you are fine. A view is only required when an implicit render is called due to execution reaching the end of the action.
No, it's really up to you and it depends on what the action will actually do. Actions can render different types content types: text, json, html, xml... etc. Here's an example:
def show
render xml: #something
end
This action doesn't have a view, but it'll output an xml when called. It can also render different things based on the format of the call:
def show
respond_to do |format|
format.html do
redirect_to '/'
end
format.json do
render xml: #something
end
end
end
The action may also redirect (again, this one doesn't have a file):
def show
redirect_to '/'
end
At the end, it's really up to the programmer to handle how the action behaves, but if you leave it empty, it'll assume there's a file to render.

How do you respond using a one-line piece of javascript in a Ruby on Rails controller action?

I haven't been able to find any useful resources online on how to do this. Basically what I'm trying to do is run a simple jQuery $('#test-div').show(); when my def show_div controller action is complete.
I've tried the following and it doesn't work. It actually renders HTML which is confusing to me. when I explicitly state that the method respond with js.
users_controller.rb
def show_div
#user = User.first
respond_to do |format|
format.js {}
end
# also tried
# render :js => "$('#test-div').show();"
end
show_div.js.erb
$('#test-div').show();
render :text should do what you are asking for -- just return raw text (which in your case happens to be JavaScript code) without doing anything to it.

Render partial from helper_method

Ok so I have a helper method in the application controller:
def run_test(test_name)
#computation stuff
render :partial => test_name
end
And I call it like so in views:
<%= run_test("testpartial") %>
and it renders ok with only 1 (although... the render partial seems to be returning an array instead of just the partial content?), but if I put the run_test helper call in the view twice I get a double render error, which shouldn't be happening with partials.
Any ideas?
render in a controller versus render in a view are different methods. The controller eventually calls render on a view, but the controller's render method itself expects to be called only once. It looks like this:
# Check for double render errors and set the content_type after rendering.
def render(*args) #:nodoc:
raise ::AbstractController::DoubleRenderError if response_body
super
self.content_type ||= Mime[formats.first].to_s
response_body
end
Note how it raises if called more than once?
When you call helper_method you give the view a proxy to the controller's version of render, which is not intended to be used in the same way as ActionView's, which is, unlike the controller's, expected to be called repeated to render partials and whatnot.
Looks like in Rails 3.2 this just works:
# application_helper.rb
def render_my_partial
render "my_partial"
end
You could try using render_to_string method in the view helper
render_to_string :partial => test_name, :layout => false

Redirecting to a 500 page when an AJAX call fails in Ruby on Rails

I'm working with an application built in Ruby on Rails with very poor error handling right now. If a controller method is executed via ajax, and that method results in a 500 (or 404 or any other response) the 500.html page is rendered and returned as the result to the AJAX request. Obviously the javascript doesn't know what to do with that HTML and the web page looks like it's just waiting for a response.
Is there an easy way in rails to render an error.rjs template anytime an error occurs during an AJAX call?
You can use respond_to inside a controller's rescue_action or rescue_action_in_public method. Consider the following controller:
class DefaultController < ApplicationController
def index
raise "FAIL"
end
def rescue_action(exception)
respond_to do |format|
format.html { render :text => "Rescued HTML" }
format.js { render :action => "errors" }
end
end
end
I solved a similar problem with authorization. I created a simple authorization controller with this action:
def unauthorizedxhr
render :update do |page|
page.replace_html("notice", :partial=>"unauthorizedxhr")
page.show("notice")
end
end
Here's the template:
<% if flash[:notice] -%>
<div id="noticexhr"><%= flash[:notice] %></div>
<% end -%>
When the authorization failed in the controller, I'd redirect to the :controller=>"authorization", :action=>"unauthorizedxhr" after setting the flash[:notice] value. This allowed me to customize the message I sent to the user, and it handled the display of the message through the render :update code above.
You could adapt this to your problem by creating an errors controller, catching any raised errors in your other controllers, then simply redirecting to :controller=>"errors", :action=>"displayxhr" when the call fails. That way, you'll have standardized your error communication mechanism but allowed yourself the ability to customize error messages by each action.
You can still use cpm's idea above, but the error's display will be handled by separate and distinct controller logic. that should make it a little easier to maintain.
Hope that helps.
-Chris
This was my final solution:
def rescue_action_in_public(exception)
response_code = response_code_for_rescue(exception)
status = interpret_status(response_code)
respond_to do |format|
format.html { render_optional_error_file response_code}
format.js { render :update, :status => status do |page| page.redirect_to(:url => error_page_url(status)) end}
end
end
This basically forwards to the correct static HTML page no matter if the request was via AJAX or normal GET/POST.
This is NOT used for normal error handling like validation etc. It's only used when something really bad happens - like an unhandled exception.
You can do like below :
in allpication.js
$(document).ready(function(){
$(document).ajaxError( function(e, xhr, options){
if("500" == xhr.status)
{
$(location).attr('href','/users/sign_in');
}
});
})
Its working for me.....

Resources