839cd40c4e78a2caf7f124f4bd2fe9f6acc5dc0a
[selectricity] / vendor / plugins / engines / lib / engines / action_mailer_extensions.rb
1 # Overriding ActionMailer to teach it about Engines...
2 module ActionMailer
3   class Base
4
5     # Initialize the mailer via the given +method_name+. The body will be
6     # rendered and a new TMail::Mail object created.
7     def create!(method_name, *parameters) #:nodoc:
8       initialize_defaults(method_name)
9       send(method_name, *parameters)
10
11
12       # If an explicit, textual body has not been set, we check assumptions.
13       unless String === @body
14         # First, we look to see if there are any likely templates that match,
15         # which include the content-type in their file name (i.e.,
16         # "the_template_file.text.html.rhtml", etc.). Only do this if parts
17         # have not already been specified manually.
18
19         templates = get_all_templates_for_action(@template)
20         
21         #RAILS_DEFAULT_LOGGER.debug "template: #{@template}; templates: #{templates.inspect}"
22
23         if @parts.empty?
24           
25           # /app/views/<mailer object name> / <action>.something.rhtml
26           
27           #templates = Dir.glob("#{template_path}/#{@template}.*")
28                     
29           # this loop expects an array of paths to actual template files which match
30           # the given action name
31           templates.each do |path|
32             # TODO: don't hardcode rhtml|rxml
33             basename = File.basename(path)
34             next unless md = /^([^\.]+)\.([^\.]+\.[^\+]+)\.(rhtml|rxml)$/.match(basename)
35             
36             template_name = basename
37             content_type = md.captures[1].gsub('.', '/')
38
39             @parts << Part.new(:content_type => content_type,            
40               :disposition => "inline", :charset => charset,
41               :body => render_message(template_name, @body))
42           end
43           unless @parts.empty?
44             @content_type = "multipart/alternative"
45             @parts = sort_parts(@parts, @implicit_parts_order)
46           end
47         end
48
49         # Then, if there were such templates, we check to see if we ought to
50         # also render a "normal" template (without the content type). If a
51         # normal template exists (or if there were no implicit parts) we render
52         # it.
53         template_exists = @parts.empty?
54         # template_exists ||= Dir.glob("#{template_path}/#{@template}.*").any? { |i| i.split(".").length == 2 }
55         template_exists ||= templates.any? do |i|
56           arr = File.basename(i).split(".")
57           (arr.length == 2) && (arr[0] == @template) 
58         end
59         @body = render_message(@template, @body) if template_exists
60
61         # Finally, if there are other message parts and a textual body exists,
62         # we shift it onto the front of the parts and set the body to nil (so
63         # that create_mail doesn't try to render it in addition to the parts).
64         if !@parts.empty? && String === @body
65           @parts.unshift Part.new(:charset => charset, :body => @body)
66           @body = nil
67         end
68       end
69
70       # If this is a multipart e-mail add the mime_version if it is not
71       # already set.
72       @mime_version ||= "1.0" if !@parts.empty?
73
74       # build the mail object itself
75       @mail = create_mail
76     end
77
78     private
79
80
81       # JGA - Modified to pass the method name to initialize_template_class
82       def render(opts)
83         body = opts.delete(:body)
84         initialize_template_class(body, opts[:file]).render(opts)
85       end
86
87       
88       # Return all ActionView template paths from the app and all Engines
89       def template_paths
90         paths = [template_path]
91         Engines.each { |engine|
92           # add a path for every engine if one exists.
93           engine_template_path = File.join(engine.root, "app", "views", mailer_name)
94           paths << engine_template_path if File.exists?(engine_template_path)
95         }
96         paths
97       end
98
99       # Returns a list of all template paths in the app and Engines
100       # which contain templates that might be used for the given action
101       def get_all_templates_for_action(action)
102         # can we trust uniq! to do this? i'm not sure...
103         templates = []
104         seen_names = []
105         template_paths.each { |path|
106           all_templates_for_path = Dir.glob(File.join(path, "#{action}*"))
107           all_templates_for_path.each { |template|
108             name = File.basename(template)
109             if !seen_names.include?(name)
110               seen_names << name
111               templates << template
112             end
113           }
114         }
115         templates
116       end
117
118       # Returns the first path to the given template in our
119       # app/Engine 'chain'.
120       def find_template_root_for(template)
121         all_paths = get_all_templates_for_action(template)
122         if all_paths.empty?
123           return template_path
124         else
125           return File.dirname(all_paths[0])
126         end
127       end
128
129       # JGA - changed here to include the method name that we
130       # are interested in, so that we can re-locate the proper
131       # template root
132       def initialize_template_class(assigns, method_name)
133         engine_template = find_template_root_for(method_name)
134         action_view_class = Class.new(ActionView::Base).send(:include, master_helper_module)
135         action_view_class.new(engine_template, assigns, self)        
136       end
137
138
139   end
140 end

Benjamin Mako Hill || Want to submit a patch?