Ruby on Rails
HowToRenderAlternateTemplatesWithActionMailer

Scenario: You have a string variable populated with an ERb template which you want to use in ActionMailer, rather than using the default method-named file-based template.

Solution: ActionView to the rescue! Add a method similar to the following to your ActionMailer model:


def email_from_template(to,from,subject,template_string,assigns={})
  email_builder = ActionView::Base.new

  recipients to
  from        from
  subject    subject

  part "text/html" do |a|
    a.body = email_builder.render(
      :inline => template_string,
      :locals => assigns
    )
  end
end

Now from anywhere in your application, you can call:


Mailer.deliver_email_from_template(
  '<a href="mailto:user@isp.com">user@isp.com</a>',
  '<a href="mailto:admin@myapp.com">admin@myapp.com</a>',
  'Email Alert',
  some_big_long_erb_string,
  { :foo => @foo, :another => @cool_object }
)

Note that there appears to be a bug in the Wiki. The above email addresses should simply be the email addresses themselves and not enclosed in HTML anchor tags.

Enjoy!

solo

I couldn’t get the above to pass varibles to the template. However, the following minor modifications (moving assings from the render call to the ActionView::Base.new call) worked for me.


email_builder = ActionView::Base.new(nil,assigns)


a.body = email_builder.render(
      :inline => template_string,
    }

— Jon

I am writing an mail sender that is fed with templates by the user and then substitutes some values in the templates. It could handle both erb and plain text templates.
For example

"<h1>A good morning wish


Good morning, <= @name>"


is an erb template. And
"hello,#{@name}"

is a string template.
I wrote a class method substitute that works with both templates.It takes a string representing the template,a hash which contains the values for the variables i.e. :name => “Izomorphius” and as last parameter a string which is either “ruby” or “rhtml” (ok – that’s not the best way to do that part but anyway that’s not the interesting part). Substitute returns the newly evaluated string(i.e. the template with substituted values).Here is the code:

require "erb"

class String
def substitute(binding=TOPLEVEL_BINDING)
eval(%{"#{self}"}, binding)
end
end

#substitutes the values in a given string or erb template with the ones given in
#args. Currently there are two valid values for type: “ruby” and “rhtml”.
class ArgumentSubstituter
def self.substitute args,template,type
args.each do |k,v|
## create and initialize an instance variable for this key/value pair
self.instance_variable_set(“@#{k}”, v)
end
if type == “ruby”
template.substitute(binding)
elsif type == “rhtml”
e = ERB.new template
e.result(binding)
end
end
end

Now here is how the template defined at run-time. I have a mailer called GoodMorningMailer and in it I have a method called send. send.rhtml is simple – it contains only @body as text. I fill @body using the above described class in my send method and everything seems ok.
—Izomorphius