rails: Setting self.response_body = nil no longer prevents DoubleRenderError
Steps to reproduce
I am attempting to prevent a AbstractController::DoubleRenderError
in a controller by setting self.response_body = nil
before a second call to render
. The reason that multiple renders occur is that I have after_action
callbacks that call render
after the action itself has already rendered its response.
It is my understanding that self.response_body = nil
should drop the previously-rendered body to allow a subsequent render call to succeed without causing a DoubleRenderError.
This works in Rails 4.2.6 but it no longer appears prevent double rendering exceptions in Rails 5+ (including current master).
This simplified example shows a scenario that properly renders ‘something else’ in Rails 4.2.6 but fails in 5.0.0.rc1 (and master):
# Rails 4.2.6
def should_prevent_double_render
render json: { foo: 'something' }
self.response_body = nil
performed? # => false
render json: { foo: 'something else' }
end
# Rails 5.0.0.rc1
def should_prevent_double_render
render json: { foo: 'something' }
self.response_body = nil
performed? # => ["{\"foo\":\"something\"}"]
render json: { foo: 'something else' }
# ... AbstractController::DoubleRenderError is raised
end
Complete gist with tests replicating this issue is available here: https://gist.github.com/kdough/c797c25088331ffc275bb2aa6159bde9
Expected behavior
Setting self.response_body = nil
before a subsequent call to render
should drop a previously-rendered response body.
Actual behavior
As of Rails 5+, a AbstractController::DoubleRenderError
exception is raised when a second call to render
is made. The previously-rendered content remains in the result of performed?
In Rails 4.2.6, the second call to render
succeeds as expected.
System configuration
- Working Setup:
- Rails version: 4.2.6
- Ruby version: 2.3.1p112
- Broken Setup:
- Rails version: 5.0.0.rc1
- Ruby version: 2.3.1p112
About this issue
- Original URL
- State: open
- Created 8 years ago
- Comments: 15 (14 by maintainers)
I just wanted to add another use case. We run into this problem when attempting to resolve a double render issue while rescuing from
ActionController::InvalidCrossOriginRequest
Maybe this should be a separate issue related to the
rescue_from
method?@matthewd @rafaelfranca Looks like the community needs a proper way of unsending a response, I’d like to make a PR introducing this functionality adding an ad-hoc method to the public API: sounds good to you?
My understanding from the conversation here and the work done on other (related?) issues is that it should be possible to reset the body as attempted by @kdough in normal requests and it should not be possible to reset the body in this way for streaming requests. /cc @matthewd & @rafaelfranca
I ran into the same issue while developing an OpenID Connect extension for the doorkeeper gem, the use-case is that certain behaviours are user-defined and might involve redirects, but in some cases I have to ignore that response and send my own. It would be nice to have a supported API for this, maybe a
reset_body!
method on the controller to mirror the one from the response.Also, as a temporary workaround the following seems to work fine on 5.0.0.1 with non-streaming responses: