This post originated from an RSS feed registered with Ruby Buzz
by Jamis Buck.
Original Post: Rails tip of the day
Feed Title: the buckblogs here
Feed URL: http://weblog.jamisbuck.org/blog.cgi/programming/index.rss
Feed Description: Jamis Buck's corner of the blogging universe. Mostly about ruby, but includes ramblings on a variety of topics.
With the release of Rails 0.13, a lot of people seem to be surprised by the appearance of the mysterious DoubleRenderError, which is suddenly popping up in their apps.
In order to understand why the DoubleRenderError was necessary, you need to understand something about the render and redirect_to methods that may surprise you. Many programmers expect a call to render or redirect_to to immediately cease execution of their action and return the result back to the browser. This is not the case in Rails. Unless you explicitly return after rendering or redirecting, your action will continue on its merry way as if nothing had happened.
Consider the following Rails action:
def do_something
render "some/action" if foo_exists?
raise "something bad"
rescue
render "something/happened"
end
If foo_exists?, some Rails programmers are expecting that the render of some/action will happen and nothing else—the action will implicitly terminate. However, that isn’t true. What happens is that the exception is raised, the rescue happens, and render is called again.
In Rails < 0.13, this would fail silently—the first action would be rendered and no one would know that “something bad happened” because the second render would have no effect—even though it was executed. Now, though, people are getting DoubleRenderError when the second render is fired.
Ultimately, DoubleRenderError will help you avoid insidious, hard-to-find bugs caused by side effects occurring after the first render or redirect. In the meantime, though, it can be very frustrating to deal with these new errors.
Here’s some tips you can try to avoid the DoubleRenderError:
When redirecting, do “redirect_to(...) and return”. This will return immediately after setting up the redirect. The same works while rendering.
Always return false in your before filters if you do a redirect or a render. This will cause the filter chain to halt immediately, preventing subsequent filters from running (which may try to do another render or redirect).
Check the value of performed?. When a render or redirect is executed, performed? is set to true. Thus, you can do things like “render(...) unless performed?”.