Two render calls in one Rails action
Question
What's the behavior of this Rails controller action?
def show
@event = Event.find(params[:id])
@event.remote? # => true
if @event.remote?
render action: "roblox_show"
end
render action: "show"
end
The correct answer is
-
It renders
"roblox_show" -
It renders
"show" - It renders both views
-
It raises
DoubleRenderErrorCorrect
Explanation
TL;DR
render does not stop the action. It sets up the response and lets the method keep running. Since @event.remote? is true, the action calls render a second time, and Rails raises AbstractController::DoubleRenderError ("Render and/or redirect were called multiple times in this action").
Why it raises
A common misconception is that render behaves like return. It does not. It marks the response as rendered and execution continues on the next line. In this action, the code path for a remote event is:
render action: "roblox_show"sets the response body.- Execution falls through the
if. render action: "show"finds the response already rendered and raisesAbstractController::DoubleRenderError.
The same rule applies to redirect_to: one response per action, whether rendered or redirected.
How to fix it
Make each code path render at most once. An explicit return after the conditional render works:
def show
@event = Event.find(params[:id])
if @event.remote?
render action: "roblox_show"
return
end
render action: "show"
end
The idiomatic one-liner is and return:
def show
@event = Event.find(params[:id])
render action: "roblox_show" and return if @event.remote?
render action: "show"
end
Or lean on implicit rendering: when an action finishes without rendering, Rails renders the template matching the action name, show here. Dropping the last render makes both paths correct:
def show
@event = Event.find(params[:id])
if @event.remote?
render action: "roblox_show"
end
end
If @event.remote? is false, the method ends without an explicit render and ActionController renders show for you.
Share this quiz
Comments
No comments yet. Be the first.