LaunchKit
All quizzes
Rails 0 views

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

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:

  1. render action: "roblox_show" sets the response body.
  2. Execution falls through the if.
  3. render action: "show" finds the response already rendered and raises AbstractController::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.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.