2012年4月26日木曜日

Ruby on Rails + RSpec 画像アップロードのテスト方法

画像をformからアップロードする時のバリデーションテストをどうするか?
という話をメモしておきます。
[環境]
CentOS6.2
Rails 3.2.2
Ruby 1.9.3-p125


(1)テスト対象のModel

前回に引き続き
簡易blog(食べたもの記録)アプリの記事本体部分を想定。
Modelの名前はDiningとします。
app_root/db/migrate/[date]_dinings.rbより抜粋すると
class CreateDinings < ActiveRecord::Migration
  def change
    create_table :dinings do |t|
      t.date :date      #日付
      t.string :time   #「朝」「昼」「夜」が入る
      t.string :menu #「食べたもの」
      t.integer :price  #「お値段」
      t.string :shop   #「店」
      t.string :place  #「店の場所」
      t.integer :evaluetion #1~5の5段階評価
      t.string :impression #感想
      t.string :ctype    # 写真が指定されている時写真のcontent_type
      t.binary :photo  #写真

      t.timestamps
    end
  end
end

写真データを直接DBに格納するモデルです。 ここでは ・画像ファイルのcontent-typeが画像で無い時バリデーションエラーになること をテストしていきます。

(2)テスト

app_root/spec/model/dining_spec.rbより抜粋
describe "写真(photo)" do
    it "content-typeが画像の時バリデーションエラーが発生しないこと" do
      @dining.data = Rack::Test::UploadedFile.new(Rails.root.join("test/fixtures/test.jpg"), "image/jpeg")
      @dining.should be_valid
    end
    it "content-typeが画像以外の時バリデーションエラーが発生すること" do
      @dining.data = Rack::Test::UploadedFile.new(Rails.root.join("test/fixtures/test.jpg"), "image/text")
      @dining.should be_valid
    end
  end

Rack::Test::UploadedFile.new()が仮想アップロードファイルをテストするためのメソッドで 第1引数にテスト画像,第2引数にcontent-typeを設定します。

(3)バリデーションの実装

テストがでけたので。 app_root/app/model/dining.rbにバリデーションを実装していきます。
#coding:utf-8
class Dining < ActiveRecord::Base

#中略

  validate :file_invalid? #写真のバリデート

  def data=(data)
    self.ctype = data.content_type
    self.photo = data.read
  end

  def file_invalid?
    if !self.photo.nil? then #写真が指定されてる時
      ps = ['image/jpeg', 'image/gif', 'image/png']
      errors.add(:photo, 'は画像ファイルではありません') if !ps.include?(self.ctype)
     end
  end

end
テスト/実装コードにもある通りフォーム側で画像をアップロードする時に、 直接model上のカラムである:imageではなく、:dataという仮のパラメータにセットして アップロード時に:ctypeと:imageを:dataから抽出してセットしている点が注意が必要。 form側では
<%= f.label :data, "写真" %> <%= f.file_field :data %>
という記述でアップロードフォームを実現しています。

0 件のコメント:

コメントを投稿