There are just some days when you want to interact with real data from a Rails application that you wrote. Doing a database dump, saving the output locally, and loading that data in is the ideal method, but once you do that, you’ve got live data locally. This can be a Bad Thing™ if you’re sending email.
Why?
Mailers can be triggered in any number of places. A callback, a controller, or an observer could be sitting there, waiting to send off an email to an unsuspecting victim without you being aware. This is one reason why playing with live data is a bit dangerous. There’s luckily an easy workaround.
ActionMailer::Base
has an instance method, recipients
, that accepts a string
of email addresses to whom you’ll be sending your message. If we override that
method in the mailer classes we don’t want sending email, we can intercept any
calls and replace recipients if we want.
class ProductMailer < ActionMailer::Base
# mailer methods
def recipients(*emails)
if emails.size == 1
super(MAILER_RECIPIENT_OVERRIDE || emails.first)
else
super(*emails)
end
end
end
Using Ruby, we overload the recipients method and call super
, passing our
MAILER_RECIPIENT_OVERRIDE
constant or the email addresses that were passed.
Because our mailer inherits from ActionMailer::Base
, super
will relay the
constant or whatever was passed; if the constant is nil
, the recipients will
work normally. However, in our development environment (for example), if that
constant is assigned a string, the email will be delivered to the email instead.
Where does this leave us?
We’re going to want to assign values to this constant for each of our
environments. In config/environments/development.rb
(or whichever environment
you dumped the live data into), we’ll want to assign this to a string. I like
sending everything to “test@example.com”. Within our other environments, we’ll
want this set to nil
so it doesn’t affect our tests or production site emails.
# config/environments/development.rb
MAILER_RECIPIENT_OVERRIDE = "test@example.com"
# config/environments/staging.rb
MAILER_RECIPIENT_OVERRIDE = "test@example.com"
# config/environments/test.rb
MAILER_RECIPIENT_OVERRIDE = nil
# config/environments/production.rb
MAILER_RECIPIENT_OVERRIDE = nil
This solution provides a quick, simple way to override recipients without cluttering up the code and allows a flexible solution when dealing with live data.
There is a caveat, however. You have to do this for every mailer. There are
ways around this (like creating an ApplicationMailer
base class that your
mailers inherit from), but unless you’re dealing with a bunch of mailers,
defining recipients in each is a perfectly acceptable solution.