Upgrading from rails 2 mailer to rails 3 without using new api

Converting all your mailers to the new api in a single commit is pretty daunting and makes them less readable / reusable since now everything has to fit into one big hash at the end of each method. This little patch keeps mailer methods that use the old api working while allowing to use the new api, a smooth transition path!

Usage

class UserMailer < ApplicationMailer::Base
  include DeprecatedMailerAPI

  def welcome
    to "me@example.com"
    from "you@example.com"
    subject "blah"
  end
end

UserMailer.deliver_welcome

Code

  module DeprecatedMailerAPI
    # call build_mail if mail was not used
    def process(*args)
      old = @_message
      super
      unless @mail_was_called
        @_message = old
        build_mail
      end
    end

    def from(xxx=:read)
      mail_cache(:from, xxx)
    end

    def recipients(xxx=:read)
      mail_cache(:to, xxx)
    end

    def cc(xxx=:read)
      mail_cache(:cc, xxx)
    end

    def bcc(xxx=:read)
      mail_cache(:bcc, xxx)
    end

    def reply_to(xxx=:read)
      mail_cache(:reply_to, xxx)
    end

    def content_type(xxx=:read)
      mail_cache(:content_type, xxx)
    end

    def body(xxx=:read)
      mail_cache(:body, xxx)
    end

    def part(options)
      key = case options[:content_type]
      when Mime::TEXT.to_s then :text
      when Mime::HTML.to_s then :html
      else
        raise "Unuspported content_type #{options[:content_type].inspect}"
      end
      @mail_cache ||= {}
      @mail_cache[:parts] ||= {}
      @mail_cache[:parts][key] = options[:body]
    end

    def subject(xxx=:read)
      mail_cache(:subject, xxx)
    end

    def build_mail
      if @mail_cache[:parts]
        mail(@mail_cache.except(:parts, :content_type)) do |format|
          @mail_cache[:parts].each do |f,b|
            format.send(f) { render :text => b }
          end
        end
      else
        mail(@mail_cache)
      end
    end

    def mail_cache(k,v)
      @mail_cache ||= {}
      if v == :read
        @mail_cache[k]
      else
        @mail_cache[k] = v
      end
    end

    def self.included(base)
      class << base
        alias_method :method_missing_without_deprecated, :method_missing

        # convert old create/deliver_foo to foo().deliver
        def method_missing(name, *args, &block)
          if match = /^(create|deliver)_([_a-z]\w*)/.match(name.to_s)
            mail = method_missing_without_deprecated(match[2], *args, &block)
            match[1] == "create" ? mail : mail.deliver
          else
            method_missing_without_deprecated(name, *args, &block)
          end
        end
      end
    end
  end

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s