Reputation: 5135
class SomeController < ApplicationController
before_action :api_limit
def new
if user.can_access_foo?
render 'foo'
end
if user.can_access_bar?
render 'bar'
end
if user.can_access_hello?
render 'hello'
end
end
def api_limit
render 'exceed_limit_error'
# code in action will not be executed.
end
end
When render
or redirect_to
exists in before_filter, action will not be executed. In short, there is no risk of double rendering.
See the Rails Guide on controllers :
If a "before" filter renders or redirects, the action will not run. If there are additional filters scheduled to run after that filter, they are also cancelled.
However, why Rails allow double rendering in an action?
Take following code as example. a Double Render Exception will raised by Rails when user can access foo
, bar
, or hello
.
class SomeController < ApplicationController
before_action :callback
def new
if user.can_access_foo?
render 'foo'
# From my understanding, following render should
# be ignored if this step is successfully performed.
end
if user.can_access_bar?
render 'bar'
end
if user.can_access_hello?
render 'hello'
end
end
end
Why not respond immediately and halt the request cycle when render 'foo'
completes? That sounds more reasonable.
Upvotes: 0
Views: 203
Reputation: 5035
The reason why a render
statement in an action doesn't return the code execution is that it is a reasonable use case that there is further (non-rendering) code to be executed after the render in the action.
The reason that a render in the before_action
callback doesn't allow code execution to go into the action is because this would assume that you have actions that have code paths that neither render nor redirect (otherwise you would get a double render error). This code path in the action is a much less reasonable use case because it would rely on the "before" filter to have triggered and performed a render already.
The intention of the structure of Rails' actions and filters in the controllers is that they are not so tightly coupled. Generally a filter will not be aware of what action will run after it, and an action is not aware of what filters triggered before it ran. So to make them coordinate as to which is doing the rendering would break that loose coupling. Each action must assume that rendering is an essential part of its role, that is why it doesn't make sense for an action to run if the filter already rendered.
Upvotes: 1