Helping out ActionMailer

ActionMailer is the “red-headed step-child” of Rails. Is it a model?
Is it a view? Is it a controller? It’s really none of the above, but
sits in no-man’s land. In addition it’s usage pattern is kind of
strange, you call the class with create_ or deliver_ in front of
the method name that represents the message you want to send!

That craziness aside, I encountered a particular problem today that
ActionMailer made rather opaque. The solution is a peek at how you
can bend Rails to your will using the power of Ruby. GiftLasso has
some frequently used helpers in the view that generate parts-of-speech
(primarily pronouns) based on the gender of the person in question. I
lumped them all in a helper called, conveniently, GenderHelper. Now
I wanted to make use of these in my ActionMailer class so we can say
things like “Joe added an iPod to his wishlist” or “Jane purchased a
shirt for herself”.

Naturally, I thought, “The ActionMailer views should have access to
methods on the class generating them. So I’ll include the helper.”

classMailer<ActionMailer::BaseincludeGenderHelper#...end

No dice. Unit tests failed left and right. Whenever it doesn’t “just
work”, I head to the source. How better to determine how it works?
Digging through ActionMailer::Base, I found this snippet at the
bottom:

Now the first temptation would be to open ActionView::Base and muck
around with it, but I don’t want to break anything that the
controllers depend on. Luckily, Ruby has the ability to extend the
class of an instantiated object (aka the singleton class). We also
have at our disposal the beautiful alias_method_chain from
ActiveSupport. So what we’ll do is intercept the creation of the
ActionView object and extend it before it renders anything. Here’s
what I came up with:

classMailer<ActionMailer::Base#...definitialize_template_class_with_includes(assigns)template=initialize_template_class_without_includes(assigns)class<<templateincludeGenderHelper# any other stuff I want to addendtemplateendalias_method_chain:initialize_template_class,:includesend

You can use this technique to add any helpers you want to ActionMailer.

The technique is part of a larger pattern called prototype-based
programming.
Ruby lets you freely mix prototype-based and inheritance-based
patterns to achieve your goal. Javascript also uses prototype-based
programming, hence the name of the library Prototype.