I don't understand the code for avoiding DoubleRenderError
The official page has this snippet:
def show
@book = Book.find(params[:id])
if @book.special?
render :action => "special_show" and return
end
render :action => "regular_show"
end
Why isn't this equivalent?
def show
@book = Book.find(params[:id])
if @book.special?
render :action => "special_show"
return
end
render :action => "regular_show"
end
Or, why isn't this used?
def 开发者_开发问答show
@book = Book.find(params[:id])
if @book.special?
render :action => "special_show" and return
else
render :action => "regular_show"
end
end
I don't understand the need for render ... and return
That's a really bad example. I'm really opposed to the and return
method of short-circuiting because a lot of people don't understand what it means, and further, it's liable to be overlooked unless you're paying careful attention.
The better approach is as you describe where you have an explicit if
statement that breaks out the two possibilities. I'd go one further to collapse this all into a single render
call with the action argument identified ahead of time:
def show
@book = Book.find(params[:id])
# Determine the template to be used for this action
render_action = @book.special? ? 'special_show' : 'regular_show'
# Render the appropriate template
render(:action => render_action)
rescue ActiveRecord::RecordNotFound
render(:action => 'not_found', :status => :not_found)
end
Also missing from the example was the trap for the find
call which can produce an exception if the record isn't found. This is a common over-sight and I'm pretty sure most people forget about it entirely. Remember you shouldn't be rendering 500 "server error" in a well designed app even when receiving bad requests.
The easiest way to avoid a double render error is to have only one render
call, after all.
They are in fact all equivalent. Your example just happened to go with the least intuitively obvious version. Not sure why, but that style is something I've seen frequently in Rails examples.
Essentially, and
is a boolean operator with really low binding precedence, so a line like expression_a and expression_b
will result in expression_a
being evaluated, and then, as long as it didn't evaluate to nil
or false
, it'll evaluate expression_b
. Since render
returns... well, something non-false - don't know what, exactly ...your example behaves exactly like render whatever; return
(or with a line break instead of the semicolon, like in the second snippet).
Personally, I prefer the third snippet, with the if/else block (which doesn't need the and return
, 'cause it's at the end of the function anyway). It's in-your-face obvious what it does, and I like that in my code.
Hope this helps!
In the first snippet, if the and return
was absent, and @book.special?
was truthy, you would get a DoubleRenderError
. That's because both the render
calls would be executed.
With that in mind, all of the snippets are equivalent in that they will prevent render
from being called twice. Also, in the last snippet, the and return
is not needed since only one of the render
's will ever get called.
精彩评论