Observer Fun
Sunday, September 6th, 2009 · 0 comments
Where I share the code I just added to this site for email notifications on new comments and messages.
Ever wanted to know how to be notified by email when someone posted a comment on your home-brew blog system?
Prerequisites
You'll need: a working mail server already set up with your Rails application. Check out Step 1: The Setup in, (A Better) Contact Form in Rails.
Step 1: Generate the Mailer and Observer
./script/generate mailer Notifications new_comment
This will create app/models/notifications.rb with a single method: #new_comment.
./script/generate observer Event
This creates app/models/event_observer.rb.
Step 2: Educate Rails
Open config/environment.rb. Anywhere inside the Rails::Initializer.run block, add:
config.active_record.observers = :event_observer
Now Rails knows about the new observer we just created.
Step 3: The Only Real Programming Involved
Open app/models/event_observer.rb, right now it's just a blank class. Let's add some magic beans to it.
class EventObserver < ActiveRecord::Observer
observe :comment
def after_create(model)
Notifications.deliver_new_comment(model)
end
end
Okay, so we make it observe the Comment model with the #observe method, and add a method to be called after #create is called, which in turns calls #deliver_new_comment method in our mailer (a dynamic method that instantiates the Notifications class, calls #new_comment and delivers the email). That's a lot of calling.
In app/models/notifications.rb, you should have a single method called new_comment.
class Notifications < ActionMailer::Base
def new_comment(sent_at = Time.now)
subject '[domain.ca] New Comment'
recipients 'you@yourdomain.ca'
from 'noreply@domain.ca'
sent_on sent_at
end
end
Basically just fill in the method to your fancy. Refer to the Complete List of Action Mailer User-Settable Attributes on Rails Guides for information on what attributes you can set.
It's possible to use the record's data for the email, but without knowing the column information of your Comment model, it's difficult.
Open up app/views/notifications/new_comment.erb. It could look like...
A new comment has been created on your awesome website! Check it out now at <%= link_to "your website", root_url %>!
And yeah...
So, if everything is working correctly, every time someone creates a comment, you should receive an email notifying you.
Make it More Complex
So you want to include more information in that email, and you also want to observe your Message model to see when someone flames you? That's easy.
Assuming your database is structured as follows:
comments:
author: string
author_email: string
content: text
messages:
name: string
email: string
subject: string
message: text
In app/models/event_observer.rb:
class EventObserver < ActiveRecord::Observer
observe :comment, :message
def after_create(model)
case model
when Comment then Notifications.deliver_new_comment(model)
when Message then Notifications.deliver_new_message(model)
end
end
end
In app/models/notifications.rb:
class Notifications < ActionMailer::Base
def new_comment(comment, sent_at = Time.now)
subject '[domain.ca] New Comment'
recipients 'you@yourdomain.ca'
from 'noreply@domain.ca'
sent_on sent_at
body :author => comment[:author],
:author_email => comment[:author_email],
:content => comment[:content]
end
def new_message(message, sent_at = Time.now)
subject '[domain.ca] New Message'
recipients 'you@yourdomain.ca'
from 'noreply@domain.ca'
sent_on sent_at
body :name => message[:name],
:re => message[:subject],
:email => message[:email],
:message => message[:message]
end
end
In app/views/notifications/new_comment.erb:
<%= @author %> <<%= @author_email %>> wrote a new comment:
---
<%= @content %>
---
In app/views/notifications/new_message.erb:
<%= @name %> <<%= @email %>> wrote a message:
Re: <%= @re %>
---
<%= @message %>
---
Boom! This is, more or less, the same code I use.
