【问题标题】:What Ruby technique does Rails use to make my controller methods render views?Rails 使用什么 Ruby 技术使我的控制器方法呈现视图?
【发布时间】:2011-05-28 06:59:59
【问题描述】:

只是好奇是否有人知道在 Rails 框架中使用什么 Ruby 技术来完成以下任务。

如果我不在 Rails 控制器上编写 index 方法,如果 URL 与该路由匹配,Rails 仍将呈现索引视图文件。这是有道理的,因为我的控制器继承自父类,它必须有自己的index 方法。

但是,如果我确实定义了一个index 方法,并且只告诉它设置一个实例变量,它仍然会呈现适当的视图。例如:

def index
  @weasels = Weasel.all

  # If I omit this line, Rails renders the index anyway.
  # If this behavior is defined in the parent class's index method,
  # it seems that by overriding the method, my index wouldn't do it. 
  # I'm not explicitly calling super to get the method from 
  # ActionController::Base, but maybe Rails is doing something like that?
  render :index
end

在纯 Ruby 中,我希望必须调用 super 才能获得这种行为。

我假设 Rails 使用某种元编程技术来保证我的控制器方法将调用super。如果是这样,任何人都可以解释一下吗?您能指出执行此操作的源代码吗?

更新

正如 Mladen Jablanović 所指出的,我最初的心智模型是错误的;控制器方法通常不会渲染视图;相反,both 控制器方法 视图渲染都由一些框架代码调用。这很明显,因为我可以使用任何名称创建控制器方法 - 例如,search - 并且 search 视图将被渲染。所以很明显,在这种情况下我并没有覆盖父方法,并且一些框架代码正在解析控制器方法名称并寻找匹配的视图。

不过,框架必须能够检测到控制器方法是否已经调用了render。所以这对我来说是另一个小谜。

【问题讨论】:

  • 我看不出super 有什么关系?我可以在控制器中定义我想要的任何方法,我不会覆盖任何现有的方法。然而,正确的视图将被隐式渲染。
  • @Mladen Jablanović - 好点。因此,控制器方法必须由其他代码调用,这些代码记下名称并查找匹配的视图。
  • 必须。不熟悉 Rails 架构,但我希望一些调度程序接受用户的请求,计算要调用的控制器/动作,调用适当的方法(如果已定义),并使用适当的视图来呈现输出(如果没有显式调用 render )。
  • @skaffman - 我打算使用“how-does-it-work”标签来区分关于如何完成某事的问题和关于幕后发生的事情的问题。我认为这适用于试图揭开框架工作原理的问题,并且我认为该标签对于浏览这种性质的问题很有用。我个人希望看到更多此类问题,尤其是关于 Rails 的问题。我要重新添加标签。如果您认为这是一个坏主意,请您发表评论解释原因吗?
  • 也许internals 标签比较合适。

标签: ruby-on-rails ruby internals


【解决方案1】:

在控制器上,有一个方法叫render_for_text。这需要一个字符串并将结果设置为响应正文。即使您不渲染为文本,渲染视图文件也只是读取文件的内容,对其进行评估,然后将其传递给render_for_text 方法。然后,该方法将一个名为@performed_render 的实例变量设置为true,这会告诉rails 控制器已经渲染了一个视图。

然后有一个名为performed? 的方法,它指示渲染操作是否已被调用。它通过检查@performed_render@performed_redirect 是否为真来做到这一点。

有了以上信息,very first line of the render method 现在应该有意义了,希望能回答您的问题:

raise DoubleRenderError, "Can only render or redirect once per action" if performed?

【讨论】:

  • 太棒了!你知道render_for_text 通常在哪里被调用吗?
  • @Nathan:看看同一个链接文件中的渲染函数。它在多个地方被调用。基本上,模式是将可渲染项转换为纯文本并传递给该方法。视图被评估为文本,json 渲染被转换为 json 文本,部分被评估为文本,等等。
【解决方案2】:

Jamis Buck 几年前写了很多关于隐式路由的文章 here

我相信您要查找的代码在 Resources 中。 Rails 会查看入站请求并(对于 RESTful 路由)在此处确定未指定的控制器和操作。

更新:控制器是 Rails 框架中非常复杂的部分。它不像单个 Ruby 类和单个方法那么简单(这就是为什么 super 并不是真正需要的,而是在调用单个方法之前和之后的一系列调用。

Rack 处理请求并将其传递给 Rails,Rails 执行路由,将操作委托给 ActionController 的实例(可能已由您编码,也可能未由您编码),然后将结果传递给渲染过程。

【讨论】:

  • 我相信 Nathan 的问题并不是真正的路由问题,而是 Rails 如何在 action 方法中没有明确的代码来确保渲染视图的情况下渲染适当的视图。跨度>
  • 同意,但这发生在上面链接的 Resource 类中。根据路由(GET /people, PUT /people/5),Rails 确定要渲染的控制器、动作和模板。
  • 我知道 Rails 自动使用路由来决定运行我的控制器的索引方法,如果我不定义索引,默认的索引方法将呈现索引模板。我想了解的是,如果我重写父类的索引方法,为什么我的索引方法除了我定义的行为之外还有行为?它来自哪里?
  • @Nathan 你知道,我从没想过那部分。我想说它发生在here 的某个地方,我想在有时间的时候深入研究一下。也许今晚......
【解决方案3】:

在渲染视图时,Rails 会使用控制器中实例变量的副本初始化相应视图模板的实例。所以实例变量实际上并没有被视图继承,而是在视图渲染之前从控制器复制到视图中。

我没有在源代码中查找确切的细节,但上面的解释至少应该概述它是如何工作的。

【讨论】:

  • 我(模糊地)理解实例变量被复制到视图中。我试图了解,如果我的 index 操作没有说要这样做,Rails 知道它应该如何渲染 index 模板。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多