Rails源代码分析(11):ActionController::Layout(2)

  1.     module ClassMethods
  2.       # If a layout is specified, all rendered actions will have their result rendered
  3.       # when the layout <tt>yield</tt>s. This layout can itself depend on instance variables assigned during action
  4.       # performance and have access to them as any normal template would.
  5.       def layout(template_name, conditions = {}, auto = false)
  6.         add_layout_conditions(conditions) 
  7.         write_inheritable_attribute "layout", template_name # 设置layout属性
  8.         write_inheritable_attribute "auto_layout", auto # 设置不需要自动
  9.       end
  10.       def layout_conditions #:nodoc:
  11.         @layout_conditions ||= read_inheritable_attribute("layout_conditions")
  12.       end
  13.       def default_layout(format) #:nodoc:
  14.         layout = read_inheritable_attribute("layout") # 获取layout
  15.         return layout unless read_inheritable_attribute("auto_layout") # 如果是当前controller设置的layout则返回layout
  16.         @default_layout ||= {}
  17.         @default_layout[format] ||= default_layout_with_format(format, layout)
  18.         @default_layout[format]
  19.       end
  20.       def layout_list #:nodoc:
  21.         Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] } # 获取所有layout页面
  22.       end
  23.       private
  24.         # 继承layout的实现
  25.         def inherited_with_layout(child)
  26.           inherited_without_layout(child)
  27.           unless child.name.blank?
  28.             layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers///, '')
  29.             # 如果子类没有layout,那么设置为自动layout
  30.             child.layout(layout_match, {}, trueunless child.layout_list.grep(%r{layouts/#{layout_match}(/.[a-z][0-9a-z]*)+$}).empty?
  31.           end
  32.         end
  33.         # 增加layout条件
  34.        def add_layout_conditions(conditions)
  35.           write_inheritable_hash "layout_conditions", normalize_conditions(conditions) 
  36.         end
  37.         # 将conditions合并
  38.        def normalize_conditions(conditions)
  39.           conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
  40.         end
  41.           # 根据格式来取得layout
  42.         def default_layout_with_format(format, layout)
  43.           list = layout_list
  44.           if list.grep(%r{layouts/#{layout}/.#{format}(/.[a-z][0-9a-z]*)+$}).empty?
  45.             (!list.grep(%r{layouts/#{layout}/.([a-z][0-9a-z]*)+$}).empty? && format == :html) ? layout : nil
  46.           else
  47.             layout
  48.           end
  49.         end
  50.     end
  1.     # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
  2.     # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
  3.     # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
  4.     # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
  5.     # 获取当前layout
  6.     def active_layout(passed_layout = nil)
  7.       layout = passed_layout || self.class.default_layout(response.template.template_format)
  8.       active_layout = case layout
  9.         when String then layout
  10.         when Symbol then send!(layout)
  11.         when Proc   then layout.call(self)
  12.       end
  13.       # Explicitly passed layout names with slashes are looked up relative to the template root,
  14.       # but auto-discovered layouts derived from a nested controller will contain a slash, though be relative
  15.       # to the 'layouts' directory so we have to check the file system to infer which case the layout name came from.
  16.       if active_layout
  17.         if active_layout.include?('/') && ! layout_directory?(active_layout)
  18.           active_layout
  19.         else
  20.           "layouts/#{active_layout}"
  21.         end
  22.       end
  23.     end
  24.     protected
  25.       def render_with_a_layout(options = nil, extra_options = {}, &block) #:nodoc:
  26.         template_with_options = options.is_a?(Hash)
  27.         if (layout = pick_layout(template_with_options, options)) && apply_layout?(template_with_options, options) # 如果能找到并且能使用
  28.           options = options.merge :layout => false if template_with_options
  29.           logger.info("Rendering template within #{layout}"if logger
  30.           content_for_layout = render_with_no_layout(options, extra_options, &block)
  31.           erase_render_results
  32.           add_variables_to_assigns
  33.           @template.instance_variable_set("@content_for_layout", content_for_layout)
  34.           response.layout = layout
  35.           status = template_with_options ? options[:status] : nil
  36.           render_for_text(@template.render_file(layout, true), status)
  37.         else
  38.           render_with_no_layout(options, extra_options, &block)
  39.         end
  40.       end
  41.     private
  42.       def apply_layout?(template_with_options, options)
  43.         return false if options == :update
  44.         template_with_options ?  candidate_for_layout?(options) : !template_exempt_from_layout?
  45.       end
  46.      
  47.       # 如果render有layout key 并且选项中没有:text:xml:json:file:inline:partial:nothing
  48.       # 并且模板没有被从layout中免除
  49.      def candidate_for_layout?(options)
  50.         (options.has_key?(:layout) && options[:layout] != false) ||
  51.           options.values_at(:text:xml:json:file:inline:partial:nothing).compact.empty? &
  52.           !template_exempt_from_layout?(options[:template] || default_template_name(options[:action]))
  53.       end
  54.       #根据layout option获取layout
  55.      def pick_layout(template_with_options, options)
  56.         if template_with_options
  57.           case layout = options[:layout]
  58.             #如果layout=>false 那么返回nil
  59.             when FalseClass
  60.               nil
  61.           # 如果是nil或者true并且拥有layout返回layout
  62.             when NilClassTrueClass
  63.               active_layout if action_has_layout?
  64.             else
  65.           # 如果没有条件直接返回当前layout
  66.               active_layout(layout)
  67.           end
  68.         else
  69.          # 没有条件 则返回
  70.           active_layout if action_has_layout?
  71.         end
  72.       end
  73.       def action_has_layout?
  74.         if conditions = self.class.layout_conditions
  75.           case
  76.           # 如果only包含=>true
  77.             when only = conditions[:only]
  78.               only.include?(action_name)
  79.             # 如果except包含=>false
  80.             when except = conditions[:except]
  81.               !except.include?(action_name)
  82.             else
  83.             #默认true
  84.               true
  85.           end
  86.         else
  87.          # 没有条件true
  88.           true
  89.         end
  90.       end
  91.       def layout_directory?(layout_name)
  92.         @template.finder.find_template_extension_from_handler(File.join('layouts', layout_name))
  93.       end


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值