11

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

如果我不在indexRails 控制器上编写方法,如果 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 Jabnović 所指出的,我最初的心智模型是错误的。控制器方法通常不会渲染视图;相反,控制器方法和视图渲染都由一些框架代码调用。这很明显,因为我可以创建一个具有任何名称的控制器方法 - 例如,- 并且视图将被渲染。所以很明显,在这种情况下我并没有覆盖父方法,并且一些框架代码正在解析控制器方法名称并寻找匹配的视图。searchsearch

尽管如此,框架必须能够检测控制器方法是否已经调用render。所以这对我来说是另一个小谜团。

4

3 回答 3

6

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

然后会调用一个方法performed?来指示是否调用了渲染操作。它通过检查是否@performed_render@performed_redirect真来做到这一点。

有了以上信息,render 方法的第一行现在应该是有意义的,希望能回答你的问题:

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

于 2010-12-20T16:47:25.187 回答
1

Jamis Buck 几年前在这里写了很多关于隐式路由的文章。

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

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

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

于 2010-12-20T14:58:05.330 回答
1

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

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

于 2010-12-20T14:49:26.170 回答