AbstractController::DoubleRenderError Fix

Sebastian Suttner
Apr 25 · 3 min read

Is this error giving you a headache? Have you already tried using and return as Rails suggests in its guides but still can’t make the error go away?

TL;DR: See if you are calling render in controller concerns. This post will explain why this might be the issue that’s right under your nose.


The key thing to understand here is that render has multiple implementations in Rails and we need to know which one is being used when.

ActionView::Renderer#render

# rails/actionview/lib/action_view/renderer/renderer.rb# Main render entry point shared by Action View and Action Controller.def render(context, options)      
if options.key?(:partial)
render_partial(context, options)
else
render_template(context, options)
end
end

In the context of a view, therender method can be called multiple times to render partials. No specific restrictions apply to this implementation, so no exceptions will be raised in this case.

ActionController::Rendering#render

# rails/actionpack/lib/action_controller/metal/rendering.rb# Check for double render errors and set the content_type after rendering.def render(*args) #:nodoc:
raise ::AbstractController::DoubleRenderError if response_body
super
end

When explicitly calling render from a controller, it checks that no other response_bodywas previously set (e.g. via render or redirect_to). If there is already a response_body, it raises AbstractController::DoubleRenderError. On the other hand, if response_body is empty, then everything works just fine.

Please note that explicitly calling render in a controller action is not obligatory. In case this does not happen, then ActionController::ImplicitRender will figure out which template to render for us.


So far so good. We now understand how the different implementations of render work.

But, it can get tricky when trying to render partials from a controller concern. It’s true that we don’t see this very often and is probably not a good code design, but I’ve come across a situation like this when working on a project. Let’s look at the next simplified example.

Calling render inside a controller concern

Suppose there is a controller concern that exposes a helper_method that renders a partial.

module Bar
extend ActiveSupport::Concern
included do
helper_method :display_bar
end
def display_bar
render partial: 'shared/bar'
end
end

Then, a controller includes this concern.

# app/controllers/foo_controller.rbclass FooController < ApplicationController
include Bar
def index
end
end

And uses its helper_method called display_bar.

# app/views/foo/index.html.erb<%= display_bar %>
<h1>Home#index</h1>
<%= display_bar %>

Why would this raise ActionController::DoubleRenderError? Are we not just trying to render partials multiple times? The answer would be: “Yes and no”.

If we had rendered the partials directly in the view, then no error would have been raised. That’s because we would have called ActionView::Renderer#render and we know it has no restrictions.

But, since we are calling a helper_method implemented in the context of a controller concern, the method will actually execute as part of the controller. It will therefore call ActionController::Rendering#render, which we know cannot be explicitly called more than once.

Conclusion

Try not to call render in controller concerns. But if you decide to do so, please be careful about ActionController::DoubleRenderError.

Cedarcode

Adding value from day one. Effective software development & expertise for your products and teams.

Sebastian Suttner

Written by

Co-founder & Software Engineer at @cedarcode

Cedarcode

Cedarcode

Adding value from day one. Effective software development & expertise for your products and teams.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade