file_columnで受信メールの添付画像を保存する方法

前提
Statusモデルにimageというフィールドがあって、そこがfile_columnを採用している。
メールを受信したら添付ファイルをstatus.imageに格納したい。


(1)file_columnの一部を拡張します。
vendor/plugins/file_column/lib/file_compat.rb
を以下のように変えます。
(- で始まる行が元々のコード、+ ではじまるのが変更後のコードです。)

   module FileCompat # :nodoc:
     def original_filename
-      File.basename(path)
+      @original_filename || File.basename(path)
     end
+
+    def original_filename=(name)
+      @original_filename = name
+    end


(2)StatusMailerというActionMailerを作る
メールを受信するためのクラスです。
中身はこんな感じ。

class StatusMailer < ActionMailer::Base  
  def receive(email)
    Status.parse_mail(email)
  end
end

メールを受信するための.forwardファイルは下記のような感じ。

RAILS_ROOT/script/runner -e production 'Status.receive(STDIN.read)'
(3)Statusモデルの中に本体を実装
  def self.parse_mail(email)

    # email.to を解析して 対象の status を割り出す。
    status = ....

    # 添付画像を取得する
    if email.multipart?
      email.parts.each do |m|
        if m.main_type == 'image'
          # file_columnへの引き渡し
          status.save_image_from_mail m
          break
        end
      end
    end
    status
  end

  def save_image_from_mail(mail_part)
    # ランダムな文字列に拡張子を付けた形でファイル名を作る
    tmp_filename = Digest::SHA1.hexdigest( rand.to_s ).slice(1..10) + '.' + mail_part.sub_type

    # Tempfileを作って、データを格納する
    tmp = Tempfile::new tmp_filename
    tmp.puts mail_part.body

    # file_columnへの引き渡し準備
    tmp.extend FileColumn::FileCompat
    tmp.original_filename = tmp_filename

    self.image = tmp
    self.save

    # 後片付け
    tmp.close
  end
(4)動作確認メーラーの適当なメールを.emlとかテキストフォーマットで保存する。 ・script/consoleを起動 ・以下を実行
$ f = open '.emlファイルのパス'
$ StatusMailer.receive(f.read)