<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Flvorful Bloggage: Deep in Rails: ActionMailer#deliver Part III</title>
    <link>http://blog.flvorful.com/articles/2009/11/29/deep-in-rails-actionmailer-deliver-part-iii</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Deep in Rails: ActionMailer#deliver Part III</title>
      <description>&lt;p&gt;When we last left off we were just about to jump into &lt;code&gt;Renderable#render&lt;/code&gt;.  That&#8217;s where we are going next:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 193 action_pack/action_view/renderable.rb)
def render(view, local_assigns = {})
  compile(local_assigns)

  view.with_template self do
    view.send(:_evaluate_assigns_and_ivars)
    view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)

    view.send(method_name(local_assigns), local_assigns) do |*names|
      ivar = :@_proc_for_layout
      if !view.instance_variable_defined?(:"@content_for_#{names.first}") &amp;&amp; view.instance_variable_defined?(ivar) &amp;&amp; (proc = view.instance_variable_get(ivar))
        view.capture(*names, &amp;proc)
      elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
        view.instance_variable_get(ivar)
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Alright, this is where we get real deep into Rails.  This particular method does the vast majority of the rendering work in Rails.  Let&#8217;s see what&#8217;s going on:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;compile(local_assigns)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the first line and it sets up a series of methods that we are going to run through. &lt;code&gt;compile&lt;/code&gt; is a private method in &lt;code&gt;Renderable&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 193 action_pack/action_view/renderable.rb)
def compile(local_assigns)
  render_symbol = method_name(local_assigns)

  if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
    compile!(render_symbol, local_assigns)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which starts out creating a method symbol for this renderable object by calling another private method aptly named &lt;code&gt;method_name&lt;/code&gt;.  This is the definition for &lt;code&gt;method_name&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 45 action_pack/action_view/renderable.rb)
def method_name(local_assigns)
  if local_assigns &amp;&amp; local_assigns.any?
    method_name = method_name_without_locals.dup
    method_name &lt;&lt; "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
  else
    method_name = method_name_without_locals
  end
  method_name.to_sym
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here are the params for our example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;local_assigns =&gt; {}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since our &lt;code&gt;local_assigns&lt;/code&gt; is empty, we end up executing the else part of the conditional which sets &lt;code&gt;method_name&lt;/code&gt; to the result &lt;code&gt;method_name_without_locals&lt;/code&gt; which is yet another private method in &lt;code&gt;Renderable&lt;/code&gt;.  Here it is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 22 action_pack/action_view/renderable.rb)
def method_name_without_locals
  ['_run', extension, method_segment].compact.join('_')
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This method gives us unique method name to use for the definition of the compiled rendered template.  You may have seen something like the following in your Rails development logs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Account Columns (251.9ms)   SHOW FIELDS FROM `accounts`
AccountSettings Columns (4.2ms)   SHOW FIELDS FROM `account_settings`
Account Load (0.5ms)   SELECT * FROM `accounts` WHERE (`accounts`.`id` = 47715) 
  app/controllers/application.rb:144:in `current_user'
  app/views/layouts/bare.rhtml:21:in `_run_rhtml_app47views47layouts47bare46rhtml'
  app/controllers/administration_controller.rb:10:in `index'
  vendor/plugins/mongrel_proctitle/lib/mongrel_proctitle.rb:114:in `process_client'
  vendor/plugins/mongrel_proctitle/lib/mongrel_proctitle.rb:33:in `request'
  vendor/plugins/mongrel_proctitle/lib/mongrel_proctitle.rb:112:in `process_client'
  vendor/plugins/mongrel_proctitle/lib/mongrel_proctitle.rb:102:in `run'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You see that line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;app/views/layouts/bare.rhtml:21:in `_run_rhtml_app47views47layouts47bare46rhtml'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the &lt;code&gt;_run_rhtml_app47views47layouts47bare46rhtml&lt;/code&gt; is actually the name of the method that is given to your template.  This is done because Rails &lt;em&gt;executes&lt;/em&gt; your template, just like any piece of Ruby code.  To do that, it needs a method name, and that is what we are doing in the &lt;code&gt;method_name_without_locals&lt;/code&gt; method, creating a unique method name for this template we are about to run. &lt;code&gt;method_segment&lt;/code&gt; is a method that is included in from &lt;code&gt;ActionView::Template&lt;/code&gt; and &lt;code&gt;extension&lt;/code&gt; is an attribute in &lt;code&gt;ActionView::Template&lt;/code&gt;.  Here is &lt;code&gt;method_segment&lt;/code&gt; and &lt;code&gt;extension&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 22 action_pack/action_view/template.rb)
def method_segment
  relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord }
end

extension =&gt; "erb"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which calls another method in &lt;code&gt;Template&lt;/code&gt; called &lt;code&gt;relative_path&lt;/code&gt; displayed here:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 172 action_pack/action_view/template.rb)
def relative_path
  path = File.expand_path(filename)
  path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT)
  path
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First, we get the full pathname to the current template and then we run &lt;code&gt;sub&lt;/code&gt; on the path to remove anything that may look like the full expanded path of &lt;code&gt;RAILS_ROOT&lt;/code&gt; if &lt;code&gt;RAILS_ROOT&lt;/code&gt; is defined.  The template&#8217;s filename is stored in the attribute &lt;code&gt;filename&lt;/code&gt;.  Here are the params:&lt;/p&gt;

&lt;pre id="scroll_to_here" &gt;&lt;code&gt;path =&gt; app/views/message_mailer/contact_form.erb
filename =&gt; /example_app/app/views/message_mailer/contact_form.erb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, the main purpose for this method is to give us the relative path to the mailer.  Now that we got our path, let&#8217;s see what &lt;code&gt;method_segment&lt;/code&gt; does to it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We call &lt;code&gt;gsub&lt;/code&gt; on the path, using the less familiar block usage.  This particular usage passes each matched string to the block for processing.  In this case, we want to match any character that isnt alphanumeric or an &#8220;_&#8221;.  We take each of these matches (which are the individual characters that matched our expression) and call &lt;code&gt;ord&lt;/code&gt; on them which returns their ASCII number.  So in our case,  &lt;code&gt;method_segment&lt;/code&gt; would end up returning &lt;code&gt;app47views47message_mailer47contact_form46erb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Good, now we have our method_segment and we know what our extension is, so let&#8217;s see what we get from &lt;code&gt;method_name_without_locals&lt;/code&gt; for our example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;_run_erb_app47views47message_mailer47contact_form46erb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whew, now we&#8217;re back to &lt;code&gt;Renderable#method_name&lt;/code&gt; with our method name and we return back from that  to &lt;code&gt;compile&lt;/code&gt;.  Let&#8217;s refresh our memories real quick:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 193 action_pack/action_view/renderable.rb)
def compile(local_assigns)
  render_symbol = method_name(local_assigns)

  if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
    compile!(render_symbol, local_assigns)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we get back for &lt;code&gt;render_symbol&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:_run_erb_app47views47message_mailer47contact_form46erb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The next section is where the super-crazy-secret-sauce magic happens, but first we have to do some checks.  First, we check to see if our &lt;code&gt;render_symbol&lt;/code&gt; is defined as a method in the module &lt;code&gt;ActionView::Base::CompiledTemplates&lt;/code&gt;.  Let&#8217;s take a gander at CompiledTemplates:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 193 action_pack/action_view/renderable.rb)
module CompiledTemplates #:nodoc:
  # holds compiled template code
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What the&#8230;.  Where is the code?  &lt;/p&gt;

&lt;p&gt;Well, remember that we just created a new method name for our template.  Why did we do that?  Because Rails needs to execute the template as with everything else.  So we have to define the method somehow so that it can be executed, right?  Exactly.  That is what &lt;code&gt;CompiledTemplates&lt;/code&gt; is for.  It&#8217;s the placeholder module where we will keep these method definitions.  Basically, it&#8217;s a nice container to hold these dynamically created methods so they arent spread out all over &lt;code&gt;ObjectSpace&lt;/code&gt;.  Plus, it makes clearing the methods cache pretty simple, just undef every method in &lt;code&gt;CompiledTemplates&lt;/code&gt;.  So first, we check to see if there is a method defined for this particular template.  Then we check the private method &lt;code&gt;recompile?&lt;/code&gt;, which is so simple, that I think it may be a placeholder for something in the future.  Here is &lt;code&gt;recompile?&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 92 action_pack/action_view/renderable.rb)
def recompile?
  false
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So basically, we are just checking the first part of our condition for the method definition.  In our case, we dont have a method defined as such and we go on to &lt;code&gt;compile!&lt;/code&gt;, which is a private method in &lt;code&gt;Renderable&lt;/code&gt; and looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 66 action_pack/action_view/renderable.rb)
def compile!(render_symbol, local_assigns)
  locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join

  source = &lt;&lt;-end_src
    def #{render_symbol}(local_assigns)
      old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
    ensure
      self.output_buffer = old_output_buffer
    end
  end_src

  begin
    ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
  rescue Errno::ENOENT =&gt; e
    raise e # Missing template file, re-raise for Base to rescue
  rescue Exception =&gt; e # errors from template code
    if logger = defined?(ActionController) &amp;&amp; Base.logger
      logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
      logger.debug "Function body: #{source}"
      logger.debug "Backtrace: #{e.backtrace.join("\n")}"
    end

    raise ActionView::TemplateError.new(self, {}, e)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we start by creating the string that will assign the local variables to their proper values and storing it in the variable &lt;code&gt;locals_code&lt;/code&gt;.  Then we move on to creating the source code that we want dynamically created and inserted into &lt;code&gt;CompiledTemplates&lt;/code&gt;.  This code uses the method &lt;code&gt;compiled_source&lt;/code&gt; which uses another method named &lt;code&gt;handler&lt;/code&gt;. &lt;code&gt;handler&lt;/code&gt; is a wrapper method for &lt;code&gt;handler_class_for_extension&lt;/code&gt; which is a class method belonging to &lt;code&gt;Template&lt;/code&gt;.  This method is defined in &lt;code&gt;TemplateHandlers&lt;/code&gt; and extended by &lt;code&gt;Template&lt;/code&gt;. All of these methods are illustrated below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 66 action_pack/action_view/renderable.rb)
def handler
  Template.handler_class_for_extension(extension)
end

def compiled_source
  handler.call(self)
end

# (action_pack/action_view/template_handlers_.rb)
module ActionView #:nodoc:
  module TemplateHandlers #:nodoc:
    ...
    def self.extended(base)
      base.register_default_template_handler :erb, TemplateHandlers::ERB
      base.register_template_handler :rjs, TemplateHandlers::RJS
      base.register_template_handler :builder, TemplateHandlers::Builder

      base.register_template_handler :rhtml, TemplateHandlers::ERB
      base.register_template_handler :rxml, TemplateHandlers::Builder
    end
    ...
    def registered_template_handler(extension)
      extension &amp;&amp; ``template_handlers[extension.to_sym]
    end
    ...
    def handler_class_for_extension(extension)
      registered_template_handler(extension) || ``default_template_handlers
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When &lt;code&gt;TemplateHandlers&lt;/code&gt; is extended it registers several extension handlers.  You are probably familiar with all of them, so we wont go into what each extension is for.  &lt;code&gt;handler_class_for_extension&lt;/code&gt; returns the result of &lt;code&gt;registered_template_handler&lt;/code&gt; or &lt;code&gt;@default_template_handlers&lt;/code&gt;. &lt;code&gt;registered_template_handler&lt;/code&gt; returns the proper handler (TemplateHandlers::ERB, TemplateHandlers::RJS or TemplateHandlers::MyCustomTemplateHandler) from the class variable &lt;code&gt;@template_handlers&lt;/code&gt; which holds the defaults plus any newly registered templates.  &lt;/p&gt;

&lt;p&gt;So we get the proper handler back (in our case &lt;code&gt;ActionView::TemplateHandlers::ERB&lt;/code&gt;) and we execute the &lt;code&gt;call&lt;/code&gt; method with our &lt;code&gt;ReloadableTemplate&lt;/code&gt; as the parameter.  &lt;code&gt;call&lt;/code&gt; is a class method in the module &lt;code&gt;TemplateHandlers::Compilable&lt;/code&gt; and included into &lt;code&gt;ERB&lt;/code&gt;. It looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 4 action_pack/action_view/template_handlers_.rb)
module Compilable
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def call(template)
      new.compile(template)
    end
  end

  def compile(template)
    raise "Need to implement #{self.class.name}#compile(template)"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we include this module we extend the base class with the module &lt;code&gt;ClassMethods&lt;/code&gt; which contains the &lt;code&gt;call&lt;/code&gt; method.  This method creates a new instance of the base class and calls the &lt;code&gt;compile&lt;/code&gt; instance method with the template.  The &lt;code&gt;compile&lt;/code&gt; in this module raises an error to let you know that it is an abstract method and needs to be defined by the base class, in our case &lt;code&gt;ERB&lt;/code&gt;.  Let&#8217;s see what &lt;code&gt;ERB&lt;/code&gt; looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 4 action_pack/action_view/template_handlers/erb.rb)
class ERB &lt; TemplateHandler
  include Compilable

  cattr_accessor :erb_trim_mode
  self.erb_trim_mode = '-'
  ...
  def compile(template)
    src = ::ERB.new("&lt;% __in_erb_template=true %&gt;#{template.source}", nil, erb_trim_mode, '@output_buffer').src
    RUBY_VERSION &gt;= '1.9' ? src.sub(/\A#coding:.*\n/, '') : src
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;compile&lt;/code&gt; is pretty simple.  We create a new instance of ERB parser and pass it the template source and the variable that we want to build the output on (&lt;code&gt;@output_buffer&lt;/code&gt;) and returning the &lt;code&gt;src&lt;/code&gt; attribute which holds the ruby code generated by the ERB parser. &lt;code&gt;@output_buffer&lt;/code&gt; is the name of an attribute inside of &lt;code&gt;ActionView::Base&lt;/code&gt; that is used as the output buffer (of course) which will get flushed when we do the final rendering (towards the end of the deliver method). In the case of an AM view, the rendering is pretty simple, but when we get to full controller views with partials we need a place to concat all the different views together which is what we use &lt;code&gt;@output_buffer&lt;/code&gt; for. The next line checks for Ruby 1.9 and does some cleaning of the result before returning it.  Here is what &lt;code&gt;src&lt;/code&gt; outputs for our example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;src =&gt; "@output_buffer = '';  __in_erb_template=true ; @output_buffer.concat \"Hi,\\n\"\n@output_buffer.concat \"\\n\"\n@output_buffer.concat \"I am contacting you with this message:\\n\"\n@output_buffer.concat \"\\n\"\n@output_buffer.concat(( `message ).to_s); @output_buffer.concat \"\\n\"\n@output_buffer.concat \"\\n\"\n@output_buffer.concat \"\\n\"\n@output_buffer.concat \"\\n\"\n@output_buffer.concat \"Thanks\\n\"\n@output_buffer.concat \"\\n\"\n@output_buffer.concat \"Jake\"; @output_buffer"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is one long string that represents the compiled version of the ruby code for our mailer view.  Now that we have the compiled_source, let&#8217;s go back &lt;code&gt;compile!&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 66 action_pack/action_view/renderable.rb)
def compile!(render_symbol, local_assigns)
  locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join

  source = &lt;&lt;-end_src
    def #{render_symbol}(local_assigns)
      old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
    ensure
      self.output_buffer = old_output_buffer
    end
  end_src
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So now we know what all the pieces mean, let&#8217;s see what our example becomes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def _run_erb_app47views47message_mailer47contact_form46erb(local_assigns)
  old_output_buffer = output_buffer;;@output_buffer = '';  __in_erb_template=true ; @output_buffer.concat "Hi,\n"
  @output_buffer.concat "\n"
  @output_buffer.concat "I am contacting you with this message:\n"
  @output_buffer.concat "\n"
  @output_buffer.concat(( `message ).to_s); @output_buffer.concat "\n"
  @output_buffer.concat "\n"
  @output_buffer.concat "\n"
  @output_buffer.concat "\n"@output_buffer.concat "Thanks\n"
  @output_buffer.concat "\n"
  @output_buffer.concat "Jake"; @output_buffer
ensure
  self.output_buffer = old_output_buffer
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Alright, now we got the code we want eval&#8217;ed, let&#8217;s keep going through &lt;code&gt;compile!&lt;/code&gt; &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 66 action_pack/action_view/renderable.rb)
def compile!(render_symbol, local_assigns)
  ...
  begin
    ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
  rescue Errno::ENOENT =&gt; e
    raise e # Missing template file, re-raise for Base to rescue
  rescue Exception =&gt; e # errors from template code
    if logger = defined?(ActionController) &amp;&amp; Base.logger
      logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
      logger.debug "Function body: #{source}"
      logger.debug "Backtrace: #{e.backtrace.join("\n")}"
    end

    raise ActionView::TemplateError.new(self, {}, e)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we open up &lt;code&gt;CompiledTemplates&lt;/code&gt; and perform a &lt;code&gt;module_eval&lt;/code&gt; with the source we just made and the filename of this template (&lt;code&gt;/example_app/app/views/message_mailer/contact_form.erb&lt;/code&gt;) and &lt;code&gt;0&lt;/code&gt;.  The filename and the number 0 are used in error reporting during &lt;code&gt;module_eval&lt;/code&gt;.  Let&#8217;s say something went wrong with the module_eval, in our case, the error would look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/example_app/app/views/message_mailer/contact_form.erb:0:in `module_eval': the real problem goes here
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#8217;s it for this week.  Next week we continue with our dynamically compiled method and see what Rails does with it.&lt;/p&gt;


</description>
      <pubDate>Sun, 29 Nov 2009 10:47:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:df11f064-42eb-4a46-a7d3-79cde9d0236b</guid>
      <author>jake</author>
      <link>http://blog.flvorful.com/articles/2009/11/29/deep-in-rails-actionmailer-deliver-part-iii</link>
      <category>Rails</category>
      <category>rails</category>
      <category>action_mailer</category>
      <category>deep</category>
      <category>DIR</category>
      <category>part3</category>
    </item>
  </channel>
</rss>

