【问题标题】:rails 3.0: ActionController::Base render()rails 3.0: ActionController::Base render()
【发布时间】:2010-01-19 15:42:21
【问题描述】:

谁能解释一下 render() 是从哪里来的 ActionController::Base?

我设法追踪到了这么远:

ActionController::Base 包含 ActionController::Rendering 模块,其中 定义了 render() 方法。然而,这个定义调用了 render() 的 超类。超类是 ActionController::Metal。其中在其 turn 继承自 AbstractController::Base。这些都没有渲染 () 定义或包含。

现在,大概它来自 AbstractController::Rendering,但我是 真的很想念它是如何被包含在内的。

【问题讨论】:

  • @artemave,您已经提出了 18 个问题,但只接受了其中四个的答案。如果答案对您有所帮助,请接受。谢谢!

标签: ruby-on-rails


【解决方案1】:

您在操作中调用的render 方法在ActionController::Base 中定义。

def render(action = nil, options = {}, &blk)
  options = _normalize_options(action, options, &blk)
  super(options)
end

此方法将调用传递给super,后者调用ActionController::Rendering 中定义的render 方法。

def render(options)
  super
  self.content_type ||= options[:_template].mime_type.to_s
  response_body
end

ActionController::Rendering 实际上是一个模块,混合到 base.rb 文件开头的 ActionController::Base 类中。

include ActionController::Redirecting
include ActionController::Rendering # <--
include ActionController::Renderers::All

反过来,ActionController::Rendering 包括 AbstractController::Rendering,正如您在 ActionController::Rendering 模块定义中看到的那样。

module ActionController
  module Rendering
    extend ActiveSupport::Concern

    included do
      include AbstractController::Rendering
      include AbstractController::LocalizedCache
    end

AbstractController::Rendering 提供了一个render 方法,它是渲染链中调用的最后一个方法。

# Mostly abstracts the fact that calling render twice is a DoubleRenderError.
# Delegates render_to_body and sticks the result in self.response_body.
def render(*args)
  if response_body
    raise AbstractController::DoubleRenderError, "Can only render or redirect once per action"
  end

  self.response_body = render_to_body(*args)
end

完整的链条是

AbstractController::Base#render 
--> super() 
--> ActionController::Rendering#render
--> super()
--> AbstractController::Rendering#render
--> render_to_body

【讨论】:

  • "super 在当前类的超类中调用与当前方法同名的方法" ActionController::Rendering 不是 ActionController::Base 的父类。它包含在模块中。那么 super 怎么会按照你描述的方式工作呢?
  • 当类 A 包含模块 B 时,B 成为 A 的祖先。参见Object#ancestors。当您在 A 中调用 super 时,它会在 A 类的所有祖先(包括 B)中搜索具有相同名称的方法。在 Ruby 中,您可以通过继承和/或使用 Mixins 来扩展类。
  • 这无疑是一个问题。
  • 因此,如果一个类包含两个定义了方法 a() 的模块,则只有一个(来自最后包含的模块)被导入。或者,更好的是,您包含的第一个模块定义了您所依赖的 a(),而第二个模块包含了一些其他模块,该模块包含了一些其他模块,该模块包含了具有方法 a() 的其他模块。保证一个艰难的调试会话。这气味太难闻了。可能值得提出自己的问题 - 人们如何解决这个问题很有趣。
  • 如果模块 AB 都定义了 foo() 并且您将 BA 包含在 C 中,它定义了它在 foo() 上,那么架构上可能有问题代码中的级别。 Ruby 默默地允许你这样做,但这并不意味着你应该这样做。 ;)
【解决方案2】:

renderAbstractController::Rendering 中定义。它调用render_to_body,后者又分派给其他方法。这有点像兔子洞,不是吗?

【讨论】:

  • 我看不出这是如何回答原始问题的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-28
  • 2015-02-15
  • 1970-01-01
  • 2018-11-02
  • 2018-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多