本文转载,来自http://ihower.tw/blog/archives/4561
新的 Rails3 Controller 重构后,变成 ActionController::Base < ActionController::Metal < AbstractController 的继承体系。除了 ActionMailer 继承自 AbstractController,让 API 与 Controller 一致之外,新的 ActionController::Metal 更是充满玩味。
故事可以从上个礼拜,Yehuda 把 Rails 2 的 Metal 移除了(commit),根据 commit 的说明,Rails 2 的 Metal 在 Rails 3 里面,可以用 1. 放在 Route 之前的 Rack middleware 或 2. 放在 Route 之后的一个 Rack endpoint,而这个 Rack endpoint,除了自己实作 Rack app,我们也可以用 ActionController::Metal 来实作出自己的客制化 Controller。
Rails2 发明 Metal 原因是,有些事情不需要完整的 Controller 功能,希望能够越快越好,例如 XML/JSON API 等。而 Rails2 的 Metal 虽然非常快,但是没什 弹性,完全不能使用 Controller 的功能,例如用 Layout, Template, Sessions 等,基本上就跟单纯的 Rack middleware 没什 两样。但是在 Rails3 中,可以透过自继承 ActionController::Metal 做出白纸般的客制 Controller,可以有非常快的速度,如果有需要用到 Controller 的功能,也可以任意选择组合加入,十分弹性。
例如,我们来实作一个超级精简的 Static Controller:
# lib/static_controller.rb class StaticController < ActionController::Metal include ActionController::Rendering append_view_path "#{Rails.root}/app/views" def about render "about" end end # config/route.rb match '/about', :to => "static#about", :as => :about
这个范例有接近于 Metal 的速度,并加入了 Controller 的 Template 功能 (你可以参考 ActionController::Base 这是拥有全部功能的版本)。其中 “static#about” 是 StaticController 的 about action 缩写,而在 Rails3 中,controller action 也都是一个 Rack app。
如果你在 Rails3 中不需要全部的 Controller 的功能,想要尽量拉高效能,有几种推荐作法:
* 写成 Rack Middleware,然后在 config/application.rb 中插入 config.middleware.use YourMiddleWare
* 写成 Rack App,在 config.route.rb 中将某个对应的网址指到这个 Rack App
* 继承自 ActionController::Metal 实作一个 Controller,其中的 action 也是一个 Rack App
其中的差异就在于后两者会在 Rails Route 之后(好处是统一由 route.rb 管理 URL 路径),如果继承自 ActionController::Metal 可以有弹性获得更多 Controller 功能。原则上,我想我会推荐 ActionController::Metal,写起来最为简单,一致性跟维护性较高。
另外,还有个小玩意, ActionController::Middleware 是 Controller 层级的 Rack Middleware,让你可以在放入到某个特定 Controller 之中(也就是只有该 Controller 使用这个 Middleware)。不过呢,这个功能我到现在还没看到任何实用的例子就是了。
最后,Yehuda 提供了一个 参考数据:
fast: through middleware inserted at 0 slwr: through middleware inserted via @use@ rotr: through endpoint sent via the router bare: through ActionController::Metal with self.response_body cntr: through ActionController::Base with self.response_body text: through ActionController::Base with render :text tmpl: through ActionController::Base with simple render :template layt: through ActionController::Base with render :template with layout real rps fast 0.004271 2900 Rack 极限 slwr 0.067029 2200 使用 config.middleware.use YourMiddleware rotr 0.088085 2000 经过 Rails Route 之后 bare 0.103868 1900 使用 ActionController::Metal 的最快速度 cntr 0.355898 1070 使用 ActionController::Base 的最快速度 text 0.557127 825 使用 ActionController::Base 加上 render :text tmpl 0.639581 765 使用 ActionController::Base 加上 render :template layt 1.678789 375 使用 ActionController::Base 加上 Template 跟 Layout