引言
Model-View-Controller(MVC)是Rails的核心架构。在Controller定义的方法中,最后一步通常是调用render函数,将Controller生成的数据渲染到指定的template, 例如:format.json { render json: @article.errors, status: :unprocessable_entity } , 那么render函数在调用时,幕后做了什么呢?让我们一起开启探索之旅吧。
Render函数调用栈
开启Byebug进入调试模式,输入step(s)进入render方法内部:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_controller/metal/instrumentation.rb
1 | 41: def render(*args) |
发现render函数嵌在Benchmark.ms方法中,于是我们就可以知道每一次render消耗的时间咯。
从44行可以看出,实际在调用父类的render()方法, step进去一探究竟吧:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/abstract_controller/rendering.rb
1 | 20: # Normalize arguments, options and then delegates render_to_body and |
_normalize_render()函数的主要作用是将用户传入的参数转换成hash。
那么render_to_body()做了什么呢?
/usr/local/rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_controller/metal/renderers.rb
1 | 36: def render_to_body(options) |
如果在/metal/renderers.rb中定义了相应格式(如json,xml)的render,则render_to_body()会调用定义的诸如_render_with_renderer_json方法。
/usr/local/rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_controller/metal/renderers.rb
1 | 40: def _render_to_body_with_renderer(options) |
如果没有定义相应格式的render, 则render_to_body()会沿着继承链一层层向上转发,最后到达ActionView::Rendering类:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionview-4.2.1/lib/action_view/rendering.rb
1 | 81: def render_to_body(options = {}) |
_render_template()方法的定义为:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionview-4.2.1/lib/action_view/rendering.rb
1 | 94: def _render_template(options) #:nodoc: |
最终的模板渲染由view_renderer.render(view_context,options)完成,其中view_context是模板解析的上下文,是ActionView::Base类型的实例。
到此为止,我们对render函数已经有了比较完整的认识,就在这里停下吧~
挑战 —— 卸载多余模块
在rails中,由Module组成的继承链是独具匠心的设计,可以让我们按照需求方便地添加和删除功能。
比如在render函数调用时,我想移除Benchmark相关的功能,可以怎么做呢?
Rails 每一个子模块,都有一个基本的base类型,比如ActionController的基本类型为ActionController::Base, 定义在gems/abstract_controller/base.rb中。在定义Base时,通过include模块的方式,定义了继承链,动态添加所需的功能。
1 | class Base < Metal |
如果我们需要移除BenchMark模块,可以这样定义controller:
1 | class MyController |
调试MyController时,会发现不再有性能分析相关的代码被执行。
关于render函数的调用,我们暂时就研究到这里,下一节让我们一起探索rails中的模板查找机制吧~