Skip to content

Instantly share code, notes, and snippets.

@jeffreyiacono
Created March 8, 2012 17:40
Show Gist options
  • Save jeffreyiacono/2002283 to your computer and use it in GitHub Desktop.
Save jeffreyiacono/2002283 to your computer and use it in GitHub Desktop.
module that extracts common mailer tasks for soundtrak.me
require 'fileutils'
require 'ostruct'
require 'pony'
require 'active_support'
module MakeEmailable
extend ActiveSupport::Concern
included do
attr_reader :sender, :receiver
attr_accessor :track
end
def initialize(options = {})
options.each do |k,v|
self.send("#{k}=".to_sym, v)
end
end
module ClassMethods
# ensure that :sender and :receiver (default mailer params) are objects
# convenience function
def ensure_default_mailer_params_are_objects
self.ensure_mailer_params_are_objects :sender, :receiver
end
# foreach param that is passed in, create a method "param=" so we can ensure
# that the corresponding instance variable is converted to an object. If the
# setter method is already defined, don't redefine it
def ensure_mailer_params_are_objects(*params)
params ||= []
params.each do |param|
method_name = "#{param}="
unless self.instance_methods.include? method_name
define_method method_name do |val|
self.instance_variable_set "@#{param}", ensure_is_object(val)
end
end
end
end
end
# read the default template file, set the instances current instance variable
# bindings, and render the template, using the variable bindings for any
# string interpolation
def body
template = File.read(default_template_filepath)
vars = bindings
renderer.new(template).result(vars.instance_eval { binding })
end
# send an email leveraging the mailer#mail method. note that this is tightly
# coupled to the specified underlying mailer
def send_email
mailer.mail(
to: self.receiver.email,
subject: self.subject,
body: self.body
)
end
private
# Reduce all instance variables to a hash with keys of the corresponding
# method name (ie. "@sender" => method key of "sender") that point to the
# method's value for the given instance.
#
# Lastly, package the hash into an OpenStruct
def bindings
OpenStruct.new(self.instance_variables.reduce({}) do |aggregator, instance_variable|
key = instance_variable.to_s.slice(1..-1)
val = self.send(key)
aggregator[key] = ensure_is_object(val)
aggregator
end)
end
# convert val to open struct if Hash, otherwise do nothing
# usage is for handling member caches and actual member objects. instead of
# detecting for hash vs obj, convert a hash cache to an obj so we can always
# use dot notation
def ensure_is_object(val)
val.is_a?(Hash) ? OpenStruct.new(val) : val
end
# return absolute path of #{APP ROOT}/views/notifiers/#{default_template_filename}
def default_template_filepath
File.expand_path('', File.join('views', 'notifiers', default_template_filename))
end
# return the demodulized and underscored current class's name with an erb ext
def default_template_filename
"#{self.class.name.demodulize.underscore}.erb"
end
# ERB is my rendering engine. There are many other rendering engines like it,
# but ERB is mine.
def renderer
ERB
end
# Can I have a Pony? (so I can send emails)
def mailer
Pony
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment