引言
上一篇中通过对render函数调用栈的学习,我们理解了controller在调用render函数时,如何找到renderer并渲染到相应的template。但是rails是如何知道应该渲染哪个模板的呢?这正是本节我们关注的问题。
Rails模板查找机制
在上一节,我们提到_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,optoins)
时,通过@lookup_cotext的find()
方法,来查找相应的template:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionview-4.2.1/lib/action_view/lookup_context.rb
1 | 120: def find(name, prefixes = [], partial = false, keys = [], options = {} ) |
进而调用定义在PathSet类中的find()
和find_all()
方法:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionview-4.2.1/lib/action_view/path_set.rb
1 | 45 def find(*args) |
最终我们在ActionView::Resolver类中找到find_all()
方法的定义:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionview-4.2.1/lib/action_view/template/resolver.rb
1 | 114 def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[]) |
cached()
方法查找template的缓存,如果找到则直接返回template,否则执行find_templates()
方法。关于template的缓存机制,我们在下一节详细介绍。
find_templates()
方法并没有在ActionView::Resolver中实现,而是在其子类中定义。如果我们想要定制自己的resolver,比如希望从数据库而非文件系统中查找template,那么就需要在自定义的resolver类型中定义find_templates()
方法,根据传入name, prefix, partial, details
参数,从数据库中取出对应的条目,生成一个ActionView::Template
对象并返回.
Rails中默认的resolver是ActionView::FileSystemResolver,从文件系统中查找template,其find_templates()
方法定义为:
/usr/local/rvm/gems/ruby-2.2.1/gems/actionview-4.2.1/lib/template/action_view/resolver.rb
1 | => 177 def find_templates(name, prefix, partial, details) |
当浏览器中访问的url为users/new
时,rails默认生成FileSystemResolver
类型的一个实例:FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
, 最终实际的template查找路径为app/views/users/new{.{en},}{.{html,js},}{.{erb,haml},}
。
我们来详细研究一下FileSystemResolver
的参数中每个字段的含义:
1 | :prefix - 通常为controller的路径 |
默认的模板查找起始路径/path/to/views
为app/views
, 可以通过ActionView::ViewPaths
中提供的append_view_path()
方法添加自定义的起始查找路径。
现在我们已经理解了Rails的模板查找机制,下一节我们将深入研究Rails的模板缓存机制。