おおいしつかさ


旅行とバイクとドライブと料理と宇宙が好き。
Ubie Discoveryのプログラマ。
Share:  このエントリーをはてなブックマークに追加

ActionMailerの個別のクラスで、interceptorみたいなことをやりたい

ActionMailerにはinterceptorという機能があって、メールを送信するときにいろいろと処理を挟むことができます。

class TsukaInterceptor  
  def self.delivering_email(message)  
    message.title = "[development] #{message.title}"  
  end  
end  

みたいなクラスを作っておいて、initializerなどで

ActionMailer::Base.register_interceptor(TsukaInterceptor) if Rails.env.development?  

とやっておけば、development環境で送信するメールのサブジェクトには、すべて [development] がつくようになります。
interceptorクラスのクラスメソッド delivering_email に渡される引数 message は、Mail::Messageクラスのオブジェクトです。

というようにinterceptorはとても便利なのですが、ActionMailer全体に影響してしまうので、個別のActionMailerクラスで別のことをやりたいときに困ります。
たとえば、あるActionMailerクラスを使ってdevelopment環境からメール送信をするときだけ、メールのあて先を変更したいとき。
interceptorを使っちゃうと全部のMailerに影響してしまうし、inteceptorクラスのdelivering_emailメソッド内で切り分けようとしても、Mail::MessageオブジェクトからはActionMailer::Baseクラスはわからないのです。

どうしようかなとちょっと悩んでtwitterでつぶやいたら、1分後くらいに元同僚のK和さんが「AbstractController::Callbacksを使ったらいいですよ」と教えてくれました。

さっそくやってみます。

class TsukaMailer < ActionMailer::Base  
  if Rails.env.development?  
    include AbstractController::Callbacks  
    after_filter :check_to  

    def check_to  
      message.to = "tsuka@example.com"  
    end  
    private :check_to  
  end  

  def hoge  
   ...  
  end  
end  

としたら、development環境のときだけ、メールのあて先がすべて check_to メソッドの中で指定したものに変わりました。
message というのは、Mail::Messageオブジェクトで、以下のように attr_internal 宣言されているのでこういうふうにアクセスできます。
https://github.com/rails/rails/blob/4-1-stable/actionmailer/lib/action_mailer/base.rb#L558