From 43d5504f0a6a831474d149aa5f1ebb2545790152 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@gmail.com>
Date: Sun, 18 Oct 2009 22:52:36 -0200
Subject: Move all render and layout pieces required in ActionMailer from
 ActionController to AbstractController.

---
 actionmailer/lib/action_mailer/base.rb             | 168 +++++++++------------
 actionmailer/test/mail_render_test.rb              |  15 +-
 actionpack/lib/abstract_controller/layouts.rb      |   9 ++
 .../abstract_controller/rendering_controller.rb    |  19 +++
 actionpack/lib/action_controller/metal/layouts.rb  |  10 --
 .../metal/rendering_controller.rb                  |  24 ---
 actionpack/test/abstract/helper_test.rb            |   4 +-
 7 files changed, 115 insertions(+), 134 deletions(-)

diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index d01120d0d8..3009d8cdfc 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -376,13 +376,19 @@ module ActionMailer #:nodoc:
     # The mail object instance referenced by this mailer.
     attr_reader :mail
     attr_reader :template_name, :default_template_name, :action_name
+    attr_internal :response_body
 
     def controller_path
       self.class.controller_path
     end
-    
+
     def formats
-      @template.formats
+      [:"*/*"]
+    end
+
+    # Refactor out all mailer_name
+    def _prefix
+      mailer_name
     end
 
     class << self
@@ -468,67 +474,68 @@ module ActionMailer #:nodoc:
     # Initialize the mailer via the given +method_name+. The body will be
     # rendered and a new TMail::Mail object created.
     def create!(method_name, *parameters) #:nodoc:
-      ActiveSupport::Notifications.instrument(:create_mail, :name => method_name) do
-        initialize_defaults(method_name)
-        __send__(method_name, *parameters)
+      initialize_defaults(method_name)
+      __send__(method_name, *parameters)
+
+      # Check if render was called.
+      @body = self.response_body if @body.is_a?(Hash) && @body.empty?
 
-        # If an explicit, textual body has not been set, we check assumptions.
-        unless String === @body
-          # TODO Hax
+      # If an explicit, textual body has not been set, we check assumptions.
+      unless String === @body
+        # TODO Fix me. Deprecate assigns to be given as a :body hash
+        if @body.is_a?(Hash)
           @body.each do |k, v|
             instance_variable_set(:"@#{k}", v)
           end
-
-          # First, we look to see if there are any likely templates that match,
-          # which include the content-type in their file name (i.e.,
-          # "the_template_file.text.html.erb", etc.). Only do this if parts
-          # have not already been specified manually.
-          # if @parts.empty?
-            template_root.find_all(@template, {}, template_path).each do |template|
-              @parts << Part.new(
-                :content_type => template.mime_type ? template.mime_type.to_s : "text/plain",
-                :disposition => "inline",
-                :charset => charset,
-                :body => render_to_string(:_template => template)
-              )
-            end
-
-            if @parts.size > 1
-              @content_type = "multipart/alternative" if @content_type !~ /^multipart/
-              @parts = sort_parts(@parts, @implicit_parts_order)
-            end
-          # end
-
-          # Then, if there were such templates, we check to see if we ought to
-          # also render a "normal" template (without the content type). If a
-          # normal template exists (or if there were no implicit parts) we render
-          # it.
-          # ====
-          # TODO: Revisit this
-          # template_exists = @parts.empty?
-          # template_exists ||= template_root.find("#{mailer_name}/#{@template}")
-          # @body = render_message(@template, @body) if template_exists
-
-          # Finally, if there are other message parts and a textual body exists,
-          # we shift it onto the front of the parts and set the body to nil (so
-          # that create_mail doesn't try to render it in addition to the parts).
-          # ====
-          # TODO: Revisit this
-          # if !@parts.empty? && String === @body
-          #   @parts.unshift Part.new(:charset => charset, :body => @body)
-          #   @body = nil
-          # end
         end
 
-        # If this is a multipart e-mail add the mime_version if it is not
-        # already set.
-        @mime_version ||= "1.0" if !@parts.empty?
+        # First, we look to see if there are any likely templates that match,
+        # which include the content-type in their file name (i.e.,
+        # "the_template_file.text.html.erb", etc.). Only do this if parts
+        # have not already been specified manually.
+        # if @parts.empty?
+          template_root.find_all(@template, {}, template_path).each do |template|
+            @parts << Part.new(
+              :content_type => template.mime_type ? template.mime_type.to_s : "text/plain",
+              :disposition => "inline",
+              :charset => charset,
+              :body => render_to_body(:_template => template)
+            )
+          end
 
-        # build the mail object itself
-        @mail = create_mail
+          if @parts.size > 1
+            @content_type = "multipart/alternative" if @content_type !~ /^multipart/
+            @parts = sort_parts(@parts, @implicit_parts_order)
+          end
+        # end
+
+        # Then, if there were such templates, we check to see if we ought to
+        # also render a "normal" template (without the content type). If a
+        # normal template exists (or if there were no implicit parts) we render
+        # it.
+        # ====
+        # TODO: Revisit this
+        # template_exists = @parts.empty?
+        # template_exists ||= template_root.find("#{mailer_name}/#{@template}")
+        # @body = render_message(@template, @body) if template_exists
+
+        # Finally, if there are other message parts and a textual body exists,
+        # we shift it onto the front of the parts and set the body to nil (so
+        # that create_mail doesn't try to render it in addition to the parts).
+        # ====
+        # TODO: Revisit this
+        # if !@parts.empty? && String === @body
+        #   @parts.unshift Part.new(:charset => charset, :body => @body)
+        #   @body = nil
+        # end
       end
 
-      @mail
+      # If this is a multipart e-mail add the mime_version if it is not
+      # already set.
+      @mime_version ||= "1.0" if !@parts.empty?
+
+      # build the mail object itself
+      @mail = create_mail
     end
 
     # Delivers a TMail::Mail object. By default, it delivers the cached mail
@@ -537,7 +544,7 @@ module ActionMailer #:nodoc:
     def deliver!(mail = @mail)
       raise "no mail object available for delivery!" unless mail
 
-      unless logger.nil?
+      if logger
         logger.info  "Sent mail to #{Array(recipients).join(', ')}"
         logger.debug "\n#{mail.encoded}"
       end
@@ -571,45 +578,16 @@ module ActionMailer #:nodoc:
         @sent_on ||= Time.now
       end
 
-      def _determine_template(options)
-        super
-        layout = options.key?(:layout) ? options[:layout] : :default
-        options[:_layout] = _layout_for_option(layout, options[:_template].details)
-      end
-
-      def render_message(method_name, body)
-        render :file => method_name, :body => body
-      ensure
-        @current_template_content_type = nil
-      end
-
-      def render(opts)
-        file = opts[:file]
-        opts[:locals] ||= {}
-
-        @template = initialize_template_class(opts.delete(:body))
-
-        if file
-          prefix = mailer_name unless file =~ /\//
-          template = view_paths.find(file, {:formats => formats}, prefix)
+      def render(*args)
+        # TODO Fix me. Deprecate assigns to be given as a :body hash
+        options = args.last.is_a?(Hash) ? args.last : {}
+        if options[:body]
+          options.delete(:body).each do |k, v|
+            instance_variable_set(:"@#{k}", v)
+          end
         end
 
-        layout = opts.key?(:layout) ? opts.delete(:layout) : :default
-        layout = _layout_for_option(layout, :formats => formats)
-
-        if template
-          @template._render_template(template, layout, opts)
-        elsif inline = opts[:inline]
-          @template._render_inline(inline, layout, opts)
-        end
-      end
-
-      def default_template_format
-        if @current_template_content_type
-          Mime::Type.lookup(@current_template_content_type).to_sym
-        else
-          :html
-        end
+        super
       end
 
       def template_root
@@ -624,12 +602,6 @@ module ActionMailer #:nodoc:
         "#{mailer_name}"
       end
 
-      def initialize_template_class(assigns)
-        template = ActionView::Base.new(self.class.view_paths, assigns, self)
-        template.formats = [default_template_format]
-        template
-      end
-
       def sort_parts(parts, order = [])
         order = order.collect { |s| s.downcase }
         
diff --git a/actionmailer/test/mail_render_test.rb b/actionmailer/test/mail_render_test.rb
index 45811612eb..3f66fb1e43 100644
--- a/actionmailer/test/mail_render_test.rb
+++ b/actionmailer/test/mail_render_test.rb
@@ -12,7 +12,15 @@ class RenderMailer < ActionMailer::Base
     recipients recipient
     subject    "using helpers"
     from       "tester@example.com"
-    body       render(:file => "signed_up", :body => { :recipient => recipient })
+    body       render(:file => "templates/signed_up", :body => { :recipient => recipient })
+  end
+
+  def implicit_body(recipient)
+    recipients recipient
+    subject    "using helpers"
+    from       "tester@example.com"
+
+    render(:template => "templates/signed_up", :body => { :recipient => recipient })
   end
 
   def rxml_template(recipient)
@@ -69,6 +77,11 @@ class RenderHelperTest < Test::Unit::TestCase
     restore_delivery_method
   end
 
+  def test_implicit_body
+    mail = RenderMailer.create_implicit_body(@recipient)
+    assert_equal "Hello there, \n\nMr. test@localhost", mail.body.strip
+  end
+
   def test_inline_template
     mail = RenderMailer.create_inline_template(@recipient)
     assert_equal "Hello, Earth", mail.body.strip
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 4723e18a01..f4f1d41360 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -157,6 +157,7 @@ module AbstractController
     end
 
   private
+
     # This will be overwritten by _write_layout_method
     def _layout(details) end
 
@@ -191,6 +192,14 @@ module AbstractController
       end
     end
 
+    def _determine_template(options)
+      super
+
+      return if (options.key?(:text) || options.key?(:inline) || options.key?(:partial)) && !options.key?(:layout)
+      layout = options.key?(:layout) ? options[:layout] : :default
+      options[:_layout] = _layout_for_option(layout, options[:_template].details)
+    end
+
     # Take in the name and details and find a Template.
     #
     # ==== Parameters
diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering_controller.rb
index bbf941aa32..9fb7935ce4 100644
--- a/actionpack/lib/abstract_controller/rendering_controller.rb
+++ b/actionpack/lib/abstract_controller/rendering_controller.rb
@@ -109,6 +109,21 @@ module AbstractController
     #   to a directory.
     # _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
     def _determine_template(options)
+      if options.key?(:text)
+        options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
+      elsif options.key?(:inline)
+        handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
+        template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
+        options[:_template] = template
+      elsif options.key?(:template)
+        options[:_template_name] = options[:template]
+      elsif options.key?(:file)
+        options[:_template_name] = options[:file]
+      elsif !options.key?(:partial)
+        options[:_template_name] ||= options[:action]
+        options[:_prefix] = _prefix
+      end
+
       name = (options[:_template_name] || action_name).to_s
 
       options[:_template] ||= with_template_cache(name) do
@@ -124,6 +139,10 @@ module AbstractController
       view_paths.exists?(name, details, options[:_prefix], options[:_partial])
     end
 
+    def _prefix
+      self.class.name.underscore
+    end
+
     def with_template_cache(name)
       yield
     end
diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb
index e7859e3fec..cc7088248a 100644
--- a/actionpack/lib/action_controller/metal/layouts.rb
+++ b/actionpack/lib/action_controller/metal/layouts.rb
@@ -167,15 +167,5 @@ module ActionController
         controller_path
       end
     end
-
-    private
-      def _determine_template(options)
-        super
-
-        return if (options.key?(:text) || options.key?(:inline) || options.key?(:partial)) && !options.key?(:layout)
-        layout = options.key?(:layout) ? options[:layout] : :default
-        options[:_layout] = _layout_for_option(layout, options[:_template].details)
-      end
-
   end
 end
diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb
index 4da32ca1b3..afd484b0ec 100644
--- a/actionpack/lib/action_controller/metal/rendering_controller.rb
+++ b/actionpack/lib/action_controller/metal/rendering_controller.rb
@@ -38,11 +38,6 @@ module ActionController
 
     def process_action(*)
       self.formats = request.formats.map {|x| x.to_sym}
-
-      super
-    end
-
-    def _determine_template(*)
       super
     end
 
@@ -74,25 +69,6 @@ module ActionController
         self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super
       end
 
-      def _determine_template(options)
-        if options.key?(:text)
-          options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
-        elsif options.key?(:inline)
-          handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
-          template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
-          options[:_template] = template
-        elsif options.key?(:template)
-          options[:_template_name] = options[:template]
-        elsif options.key?(:file)
-          options[:_template_name] = options[:file]
-        elsif !options.key?(:partial)
-          options[:_template_name] = (options[:action] || action_name).to_s
-          options[:_prefix] = _prefix
-        end
-
-        super
-      end
-
       def _process_options(options)
         status, content_type, location = options.values_at(:status, :content_type, :location)
         self.status = status if status
diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb
index 5a363c9aa5..b6952d2758 100644
--- a/actionpack/test/abstract/helper_test.rb
+++ b/actionpack/test/abstract/helper_test.rb
@@ -7,10 +7,12 @@ module AbstractController
       include AbstractController::RenderingController
       include Helpers
       
+      def _prefix() end
+
       def render(string)
         super(:_template_name => string)
       end
-      
+
       append_view_path File.expand_path(File.join(File.dirname(__FILE__), "views"))
     end
    
-- 
cgit v1.2.3