Back to Blog

Get in Touch

DRY Internal and External Notifications using ActionMailer

By Pradeep Elankumaran August 1, 2007 in rails, tips, actionmailer, hacks

Missing

I know that most Rails developers have come across the problem of notifying people by email that they have an internal message on your app’s own messaging system. Usually this is easy enough, and elegantly done in your model by using

class InternalMessage < ActiveRecord::Base
  after_save :notify_person_of_new_internal_message
  
  protected
  def notify_person_of_new_internal_message
     MyMailer.deliver_new_posting(self.from_person, self.message)
  end
end

However, let’s consider a situation where you need duplication of data on two different processes. For example, if you would like to generate a notification message when some posts to a common forum. The quick way to do this would be by calling two separate methods in your controller, like so:

subject = "Ted Stevens has posted a new topic"
body = "From Ted Stevens: " +
        "'I hope you get this, the tubes have been acting up recently!'"
@person.save_to_inbox(subject, body)
MyMailer.deliver_new_posting(@person, subject, body)

This requires you to generate the subject and the body of the message and use the methods to work out the logic.

However, with a little ActionMailer hackery, you can make this scheme much cleaner.

MyMailer.notify(person, :new_posting, from_person, note)

In your model,

class MyMailer < ActionMailer::Base
  class << self
     def notify(person, method, *params)
        new_mailer = new
        new_mailer.create!(method, *params)
        mail = new_mailer.mail
        person.save_to_inbox(mail.subject, mail.body)
        deliver(mail) if person.wants_email_notification?
     end
  end

  def new_posting(from_person, note)
     from from_person.email
     subject "#{from_person.name} has posted a new topic"
     @body[:from] = from_person
     @body[:note] = note
  end
end

Next, in views/my_mailer/new_posting.rhtml

From <%= @from_person %>: <%= @note %>

The following three lines generate a new MyMailer object, create the email specified by the method (in this case, :notify_posting) using ActionMailer’s create! method (which in turn uses Ruby’s glorious send method), and pull out the TMail object that ActionMailer sends to the SMTP server. Conveniently, the TMail object lets you extract out the subject and body, which lets you map them to your InternalMessage class.

new_mailer = new
new_mailer.create!(method, *params)
mail = new_mailer.mail

The above code generates the email, pulls out the generated subject and the body and uses it as the subject and body of the internal message. The idea is that the content of both the email notification and the internal email match up. This method does not require you to setup your subject and body. Instead, this method lets you use ActionMailer as a rendering framework for generating text/html for all of your internal messages. DRY is Good!

Medium

Pradeep Elankumaran

A former computational scientist, Pradeep was writing sophisticated astrophysical simulations in Ruby well before the language became fashionable. Since then, he has been working with and thinking a lot about social networks, machine learning and applying mathematical models to social data. At Intridea, he's responsible for researching and developing emerging web technologies, launching new products and writing beautiful code. He's also a member of the XMPP Standards Foundation.

More posts by Pradeep Elankumaran

Pradeep Elankumaran

Pradeep Elankumaran

Pradeep Elankumaran

Here's why, in no particular order, we think the

About Us

Intridea is based in Washington, D.C. Most of us live in the DC-MD-VA metro area, though we also have team members in California, Colorado, Kansas, Maine, Minnesota, Missouri, New Hampshire, New York, Pennsylvania, Wisconsin and Wyoming.

Interested in working with us, or have a question?
Feel free to contact us anytime.

© 2013 Intridea, Inc. All Rights Reserved.

Contact Us

DC Office
1020 16th Street NW
7th Floor
Washington, DC 20036
Phone
1-888-968-IDEA (4332)
1-888-968-IDEA (4332)
Email
info@intridea.com
Fax
1-202-280-1472
Twitter
@intridea

Contact Us

DC Office
1020 16th Street NW
7th Floor
Washington, DC 20036
Phone
1-888-968-IDEA (4332)
1-888-968-IDEA (4332)
Get in Touch
Email
info@intridea.com
Fax
1-202-280-1472
Twitter
@intridea

© 2013 Intridea, Inc. All Rights Reserved.

We're Hiring! Directions to office