attachment-fu/RMagick で画像アップロードサービス(その2)
アップロード系のデータ fixture_file_upload
models/photo_spec.rb
it "should be valid" do # fixtures :photos # photos(:one).should be___ uped = fixture_file_upload './ccc.jpg', 'image/pjpeg' photo = Photo.new :uploaded_data => uped photo.should be_valid end
fixture_file_upload を使うとアップロードされたファイルと同じ想定にできる。
というわけでスペック内で使えるように beforeで準備するようにしておく。
models/photo_spec.rb
before(:each) do @photo = Photo.new @uped = fixture_file_upload './ccc.jpg', 'image/pjpeg' @valid_photo = Photo.new :uploaded_data => @uped end
Photo#thumb と #small
モデルにサムネールオブジェクトを得るメソッドを追加。
models/photo_spec.rb
it 'should have a thumb method' do @valid_photo.save @valid_photo.should respond_to(:thumb) lambda{ @var = @valid_photo.thumb }.should_not raise_error @var.should be_instance_of(Photo) @var.parent_id.should == @valid_photo.id @var.thumbnail.should == 'thumb' end # it 'should have a thumb method' do it 'should have a small method' do @valid_photo.save @valid_photo.should respond_to(:small) lambda{ @var = @valid_photo.small }.should_not raise_error @var.should be_instance_of(Photo) @var.parent_id.should == @valid_photo.id @var.thumbnail.should == 'small' end # it 'should have a small method' do
models/photo.rb
class Photo < ActiveRecord::Base rails_conf = Rails::Configuration.new data_conf = rails_conf.database_configuration[rails_conf.environment] thumbnails = {:thumb => '60x', :small => '240x'} has_attachment :storage => :file_system \ , :path_prefix => data_conf['photo_path'] \ , :content_type => :image \ , :max_size => 1.megabytes \ , :thumbnails => thumbnails validates_as_attachment thumbnails.keys.each do |name| eval <<-EOdef def #{name} thumbnails.find :first, :conditions => {:thumbnail => '#{name}'} end # def #{name} EOdef end # thumbnails.keys.each do |name| end
thumbnailsハッシュを導入したのは兎も角、それで evalを回すのはやり過ぎか。
そうすると、ビューは show_thumbや、show_smallといったアクションを呼ぶような参照をしなくてもよくなる。
views/photos/show.html.erb_spec.rb
<before に追加> @small = mock_model(Photo) @photo.stub!(:small).and_return(@small)
response.should have_tag('img') #response.should have_tag('img[src=?]', "/photos/#{@photo.id}/show_photo") #response.should have_tag('img[src=?]', "/photos/#{@photo.id}/show_small") response.should have_tag('img[src=?]', "/photos/#{@photo.small.id}/show_photo") response.should have_tag('a[href=?]', "/photos/#{@photo.id}/show_photo")
views/photos/show.html.erb
<%= tag 'img', :src => url_for(:action => :show_photo, :id => @photo.small) %>
views/photos/index.html.erb_spec.rb
<before に追加> @thumb_98 = mock_model(Photo) photo_98.should_receive(:thumb).and_return(@thumb_98) < 略 > @thumb_99 = mock_model(Photo) photo_99.should_receive(:thumb).and_return(@thumb_99)
response.should have_tag('tr>td>img[src=?]', "/photos/#{@thumb_98.id}/show_photo") response.should have_tag('tr>td>img[src=?]', "/photos/#{@thumb_99.id}/show_photo")
views/photos/index.html.erb
<td><%= tag 'img', :src => url_for(:action => 'show_photo', :id => photo.thumb) %></td>
そしたらコントローラの show_thumb, show_small アクションは削除。
結局の所、ビューで url_for(:action => 'show_photo', :id => photo.thumb) と呼ぶのか url_for(:action => 'show_thumb', :id => photo) と呼ぶかの違いであり、
コントローラにメソッド増やすのとモデルにメソッド増やすのでは後者の方が見通しが良さそうなので。
indexでサムネールは持って来ない
それと、photosテーブルにはサムネールも入ってくるけど一覧には出さない。
controllers/photos_controller_spec.rb
<describe "handling GET /photos"> it "should find all photos" do #Photo.should_receive(:find).with(:all).and_return([@photo]) do_get end it "should find all photos without thumbnails" do Photo.should_receive(:find).with(:all \ , :conditions => {:thumbnail => nil} ).and_return([@photo]) do_get end # it "should find all photos without thumbnails" do
<describe "handling GET /photos.xml"> it "should find all photos without thumbnails" do #Photo.should_receive(:find).with(:all).and_return(@photos) Photo.should_receive(:find).with(:all \ , :conditions => {:thumbnail => nil} ).and_return(@photos) do_get end
controllers/photos_controller.rb
# GET /photos # GET /photos.xml def index @photos = Photo.find(:all, :conditions => {:thumbnail => nil}) respond_to do |format| format.html # index.html.erb format.xml { render :xml => @photos } end end
attachment-fu と RMagick を使った画像アップロードサービス(の原型)としてこのくらいで一区切りかな。