贴代码:
- module CompiledTemplates #:nodoc:
- # holds compiled template code
- end
- include CompiledTemplates
- # Maps inline templates to their method names
- cattr_accessor :method_names
- @@method_names = {}
- # Map method names to the names passed in local assigns so far
- @@template_args = {}
- # Cache public asset paths
- cattr_reader :computed_public_paths
- @@computed_public_paths = {}
- class ObjectWrapper < Struct.new(:value) #:nodoc:
- end
- def self.helper_modules # 这个类方法可以获得所有的rails自带的helper module的Module名
- helpers = []
- Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
- next unless file =~ /^([a-z][a-z_]*_helper).rb$/
- require "action_view/helpers/#{$1}"
- helper_module_name = $1.camelize
- if Helpers.const_defined?(helper_module_name)
- helpers << Helpers.const_get(helper_module_name)
- end
- end
- return helpers
- end
- def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
- @assigns = assigns_for_first_render
- @assigns_added = nil
- @controller = controller
- @finder = TemplateFinder.new(self, view_paths)
- end
- # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
- # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
- # is made available as local variables.
- def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
- if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
- raise ActionViewError, <<-END_ERROR
- Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
- render "user_mailer/signup"
- render :file => "user_mailer/signup"
- If you are rendering a subtemplate, you must now use controller-like partial syntax:
- render :partial => 'signup' # no mailer_name necessary
- END_ERROR
- end
- Template.new(self, template_path, use_full_path, local_assigns).render_template
- end
- # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
- # The hash in <tt>local_assigns</tt> is made available as local variables.
- def render(options = {}, local_assigns = {}, &block) #:nodoc:
- if options.is_a?(String)
- render_file(options, true, local_assigns) # 如果是String,当作render_file处理
- elsif options == :update
- update_page(&block)
- elsif options.is_a?(Hash)
- use_full_path = options[:use_full_path]
- options = options.reverse_merge(:locals => {}, :use_full_path => true)
- if partial_layout = options.delete(:layout)
- if block_given?
- wrap_content_for_layout capture(&block) do
- concat(render(options.merge(:partial => partial_layout)), block.binding)
- end
- else
- wrap_content_for_layout render(options) do
- render(options.merge(:partial => partial_layout))
- end
- end
- elsif options[:file]
- render_file(options[:file], use_full_path || false, options[:locals])
- elsif options[:partial] && options[:collection]
- render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals])
- elsif options[:partial]
- render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
- elsif options[:inline]
- template = InlineTemplate.new(self, options[:inline], options[:locals], options[:type])
- render_template(template)
- end
- end
- end
- def render_template(template) #:nodoc:
- template.render_template
- end
- # Returns true is the file may be rendered implicitly.
- def file_public?(template_path)#:nodoc:
- template_path.split('/').last[0,1] != '_'
- end
- # Returns a symbolized version of the <tt>:format</tt> parameter of the request,
- # or <tt>:html</tt> by default.
- #
- # EXCEPTION: If the <tt>:format</tt> parameter is not set, the Accept header will be examined for
- # whether it contains the JavaScript mime type as its first priority. If that's the case,
- # it will be used. This ensures that Ajax applications can use the same URL to support both
- # JavaScript and non-JavaScript users.
- def template_format # 从request中得到template格式
- return @template_format if @template_format
- if controller && controller.respond_to?(:request)
- parameter_format = controller.request.parameters[:format]
- accept_format = controller.request.accepts.first
- case
- when parameter_format.blank? && accept_format != :js
- @template_format = :html
- when parameter_format.blank? && accept_format == :js
- @template_format = :js
- else
- @template_format = parameter_format.to_sym
- end
- else
- @template_format = :html
- end
- end
- private
- def wrap_content_for_layout(content)
- original_content_for_layout = @content_for_layout
- @content_for_layout = content
- returning(yield) { @content_for_layout = original_content_for_layout }
- end
- # Evaluate the local assigns and pushes them to the view.
- def evaluate_assigns # 这个方法在template里会调用、在controller里render :update的时候调用
- unless @assigns_added
- assign_variables_from_controller
- @assigns_added = true
- end
- end
- # Assigns instance variables from the controller to the view.
- def assign_variables_from_controller # 把controller的实例变量定义复制到view里
- @assigns.each { |key, value| instance_variable_set("@#{key}", value) }
- end
- def execute(template) # 执行template生成页面
- send(template.method, template.locals) do |*names|
- instance_variable_get "@content_for_#{names.first || 'layout'}"
- end
- end