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
当render
或redirect_to
存在于before_filter中时,将不会执行操作。简而言之,不存在双重渲染的风险。
如果“之前”过滤器呈现或重定向,则操作将不会运行。如果计划在该过滤器之后运行其他过滤器,则它们也会被取消。
但是,为什么Rails允许在动作中进行双重渲染?
以下面的代码为例。当用户可以访问foo
,bar
或hello
时,Rails将引发Double Render Exception。
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
当render 'foo'
完成时,为什么不立即响应并停止请求周期?这听起来更合理。
动作中的render
语句不返回代码执行的原因是,在动作中呈现之后还有一些(非呈现)代码要执行,这是一个合理的用例。
before_action
回调中的渲染不允许代码执行进入操作的原因是因为这会假设您的操作具有既不渲染也不重定向的代码路径(否则您将获得双渲染错误)。操作中的此代码路径是一个不太合理的用例,因为它依赖于“之前”过滤器已经触发并执行了渲染。
Rails在控制器中的动作和过滤器结构的意图是它们没有紧密耦合。通常,过滤器不会知道在它之后将运行什么操作,并且操作不知道在它运行之前触发了哪些过滤器。因此,为了使它们协调哪个正在进行渲染会破坏松耦合。每个动作都必须假设渲染是其角色的重要组成部分,这就是为什么在已经渲染过滤器的情况下运行动作没有意义。