Using ActionMailer for internal messaging 14/11/2009
Rendering internal messages inline can be quite confusing, especially if you want to use some helpers inside (like path helpers). It’d be more convenient to render them in the same way as other messages – using ActionMailer and ERB templates. My solution uses email addresses to figure out the message recipients:
class UserNotifier < ActionMailer::Base
# sample message
def some_message(user)
from %Q{"Internal Messaging System"}
recipients user.email
subject "This is internal message"
body :user => user
end
# sample message notification
def message_notification(message)
from %Q{"MyAppName.com mailer"}
recipients message.recipient.email
subject "You've new message in your inbox"
body :user => user
end
private
# if the called method has "deliver_internal_"
# prefix, use notify method to deliver message
def self.method_missing(method_name, *args)
if method_name.to_s =~ /^deliver_internal_([_a-z]\w*)/
new($1, *args).send(:deliver_internal)
else
super
end
end
# deliver message to user using internal messaging
def deliver_internal
users = User.find_all_by_email(@mail.to)
from = @mail.from.first[1..-2] # remove quotes
users.each do |user|
Message.create!(:recipient => user,
:subject => @mail.subject,
:body => @mail.body,
:sender_name => from)
end
end
end
Additionally you can notify the user about a new message, by implementing a simple callback in the Message model.
class Message < ActiveRecord::Base
after_create :deliver_notification
belongs_to :recipient, :class_name => "User"
private
def deliver_notification
# deliver message notification email (external)
# if the user wants it
if recipient.wants_message_notifications?
UserNotifier.deliver_message_notification(self)
end
end
end
There’s a really good point of this solution – you don’t need to create separate actions for external and internal messaging. The only difference is the method’s prefix:
# send message and notify by email if user wants it UserNotifier.deliver_internal_some_message(user) # send email only UserNotifier.deliver_some_message(user)