My rails app has a global rescue method in application_controller which catches any errors and displays a nice looking 500 page.
This works for most exceptions, but I can't find a way gracefully handle a DoubleRenderError. It does not seem possible to render the nice 500 page because attempting to do so will throw a new DoubleRenderError from within the global rescue method.
Does anybody know of a way to "throw out" previous renders so I can render the 500 page?
You should be able to structure your code so that this type of error is impossible - how are you managing to get 2 renders in the same action?
Related
In testing, a call to session.get root_path is returning a 500 error code, i.e. assert session.response.success? is failing.
This used to be fine, so clearly I have broken something, but I’m having trouble narrowing down the cause for the following reasons:
No exception is being thrown.
The value of session.response.body is correct (i.e. it contains the correctly-rendered HTML I was expecting from the render template: ... call in the controller.
In other words, nothing appears to have actually gone wrong, but still there is a 500 HTTP response.
Note: I am setting status = :success (or some other value) earlier in the controller action, which is then passed to render as status: status. This is because I am detecting possible unauthorized access based on some stuff in the session.
Okay, I’ve been unobservant. The method for testing is called #success?, but the response code symbol is called :ok.
To be fair, the other Rails test methods / response code symbols tend to map directly.
Clarification:
So based on Max’s comment, the point here is that #success? returns true for any of the 200-family ‘happy’ HTTP codes. It is an umbrella term though, and so cannot be passed to render.
I have updated the relevant code to something more like:
status = :ok # This was :success
if redirecting_from_access_denied?
status = :unauthorized
end
I have a use case question. In Rails 4.1 if you run a controller method and have redirect_to or render at some point in your method you are still allowed to continue execution at that point. Sometimes this results in a AbstractController::DoubleRenderError if you dont handle your control flow properly. Why is this allowed in Rails? It seems like a funny use case to redirect and not stop execution, when would this be appropriate?
The full error message is listed below:
AbstractController::DoubleRenderError:
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".
Actually the error message is saying it all:
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".
This is the default Rails behaviour.
If you try to render more than one view in a single action, you will get the AbstractController::DoubleRenderError error.
To stop the execution after a render, you have to use return statement explicitly.
I have an exception handler (registered with rescue_from) which sometimes causes Double Render errors because the real action has already rendered/redirected before the exception is thrown.
To prevent this exception, I'm looking for the modern equivalent of erase_results. It cleared any rendering/redirecting activity in the current request. Not sure why it was deprecated as it seems useful. Anyway, I've tried to reconstruct it by digging into the original source, but some of the detail has changed too, so it would be a hack and I'd rather do it cleanly.
Rails uses controller#response_body to decide if the request is already rendered or redirected. Just set response_body to nil to avoid this error. Note: arguably better way is to prevent multiple rendering or redirecting at first place.
See: #render
I have a fairly complex view that has multiple forms, lots of validations on those forms, paginations, and other features. When validations fail, I like to use render because then you can be more specific about what errors occurred in the forms. However, when I use render different compiler errors crop up such as "undefined method `total_pages' for []:Array" and "undefined model_name". Is this a situation when I have to use redirect_to or is it feasible to somehow work around the errors that are coming up when the view is being rendered. Thanks a bunch!
You should grasp things in their perspective.
Why is render used instead of redirect:
when you use render, you pass the instantiated object
this object, newly created or updated, received some params
when attempting to save the object, validation was triggered and, if unsuccessful, added errors to the current instance
so your object in memory contains validation errors.
But when you use redirect, you restart with a fresh stack which doesn't know anything about the former object in memory, there could not be any magic:
either the object is saved and you can get the persisted data from database
or if it's not saved, you can have some information you previously stored in session
To answer your question a bit closer: before you use render, you have to instantiate all objects needed by the page.
It's just logic the view fails if the expected instance variables are missing.
First, these are not compiler error - its run-time errors.
Second, you should either check your data in the controller to make sure its being served properly for rendering OR do some conditional blocks in the view in order to cope with this different data structures.
Lastly, redirect_to is just a technique of moving the user around, it could be used here but you still need to handle those errors, even in the redirected-to page...
HTH
I have a controller MyController that some of his actions cannot return full HTML pages but only the content without HTML/HEAD/BODY ...tags.
The default error pages are 500.html etc. are indeed full HTML pages and for these MyController:actions I need to somehow get the error pages in a non-full page format.
One way of doing it is:
Override the "render_optional_error_file()" inside the MyController and redirect in case the action is one my special actions to a different version of the error pages (content only, non-full page tags).
Will this work? any other way out there?
BTW: I am working with rails 2.3.9.
Thanks,
Erez
It's a bit of a difficult problem, particularly in the case of the 500 error. Since the 500 will render when the application encounters and error, you can't/shouldn't have a dynamic page that is handled by a controller - since this controller could be the source of the problem.
However, in the case of the 404, you could setup an ErrorsController with a 404 action, and use a different layout, depending on whether or not the request was an XHR request or not.
Then all you need is a method in your ApplicationController like:
def render_404
render "errors/404", :status => 404
end
Which will allow you to call your custom error handler wherever you like.
You could extend this further to add support for the 500 error too (where appropriate) but keep in mind that you will always need the static 500.html in your public folder, incase of a larger problem.