This code uses a "attr_accessor :file" in the recipe model. file is not a table field, it's just a temporary variable for storing the data, before I load it into RMagick.
def do_upload_image image_types = ["image/jpeg", "image/pjpeg", "image/gif", "image/png", "image/x-png"] @recipe = Recipe.find(params[:id]) @recipe.update_attributes(params[:recipe]) logger.info "@recipe.file = " + @recipe.file.to_s if !@recipe.file.blank? if (@recipe.file.size != 0) logger.info "content_type = " + @recipe.file.content_type.to_s logger.info "size = " + @recipe.file.size.to_s if (image_types.include?@recipe.file.content_type.chomp) if @recipe.file.size < 2097152 @recipe.file.rewind # Load the file field directly into the blob, straight from memory and into RMagick! No need to write the raw file out to the filesystem pic = Magick::Image.from_blob(@recipe.file.read)[0] # I want to place the image inside a 200x200 jpg, with a white background. # so all my images are the same size, while maintaning proportions. width = pic.columns height = pic.rows if (width > height) pic.scale!((200.0/width.to_f)) else pic.scale!((200.0/height.to_f)) end back = Magick::Image.new(200,200) { self.background_color = 'white' self.format = 'JPG' } back.composite!(pic, Magick::CenterGravity, Magick::InCompositeOp) # Now scale this down for a thumbnail thumb = back.scale(50,50) # Add a rand to the filename, so if we upload a new image, we're shown it, instead of whatever we have cached. rand = Kernel.rand(1000).to_s File.open(RAILS_ROOT + "/public/images/recipes/" + @recipe.id.to_s + "-" + rand + ".jpg", "wb") do |f| f.write(back.to_blob) end File.open(RAILS_ROOT + "/public/images/recipes/" + @recipe.id.to_s + "-" + rand + "t.jpg", "wb") do |f| f.write(thumb.to_blob) end @recipe.picture = "/images/recipes/" + @recipe.id.to_s + "-" + rand + "." + "jpg" @recipe.thumbnail = "/images/recipes/" + @recipe.id.to_s + "-" + rand + "t." + "jpg" @recipe.file = nil @recipe.save flash[:notice] = 'Image Uploaded and Thumbnailed' redirect_to :action => "edit", :id => @recipe #session[:recipe] = @recipe else flash.now[:error] = "File size greater then 2 Megabytes, please upload a smaller file." render :action => 'upload_image', :id => @recipe end else flash.now[:error] = "File doesn't seem to be JPG, GIF, or PNG, please ensure it is a valid image file." render :action => 'upload_image', :id => @recipe end else flash.now[:error] = "Unable to upload the file you selected, please try again." render :action => 'upload_image', :id => @recipe end else flash.now[:error] = "Unable to upload the file you selected, please try again." render :action => 'upload_image', :id => @recipe end end
It must be nice to not have the guilt of breaking things into smaller components, loosely joined. I'd definitely not want to be the developer writing tests for this thing!