generic file and image models for uploaded files
This is my first code dealing with uploads and rmagick, so please comment if you have suggestions.
1 class DbFile < ActiveRecord::Base 2 IMAGE_TYPES = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png'] 3 before_validation :sanitize_filename 4 validates_presence_of :size, :filename, :content_type 5 6 class << self 7 def new_file(file_data) 8 content_type = file_data.content_type.strip 9 (IMAGE_TYPES.include?(content_type) ? DbImage : DbFile).new \ 10 :data => file_data.read, 11 :filename => file_data.original_filename, 12 :size => file_data.size, 13 :content_type => content_type 14 end 15 end 16 17 protected 18 def sanitize_filename 19 # NOTE: File.basename doesn't work right with Windows paths on Unix 20 # get only the filename, not the whole path 21 filename.gsub! /^.*(\\|\/)/, '' 22 23 # Finally, replace all non alphanumeric, underscore or periods with underscore 24 filename.gsub! /[^\w\.\-]/, '_' 25 end 26 end 27 28 require 'rmagick' 29 require 'base64' 30 class DbImage < DbFile 31 def data=(file_data) 32 with_image(file_data, true) do |img| 33 self.width = img.columns 34 self.height = img.rows 35 end 36 end 37 38 def with_image(file_data = nil, save_image = false, &block) 39 img = Magick::Image::read_inline(Base64.b64encode(file_data || self.data)).first 40 block.call(img) 41 write_attribute('data', img.to_blob) if save_image 42 img = nil 43 GC.start 44 end 45 end
Controller Usage:
1 # returns DbImage if content_type matches 2 db_file = DbFile.new_file(params[:file][:data]) 3 db_file.save
Model Usage:
1 # raw binary image data 2 File.open('my_file', 'w') { |f| f.write(db_file.data) } 3 4 # Image resizing with rmagick 5 # automatically creates RMagick::Image and 6 # invokes GC.start 7 db_file.with_image do |img| 8 img.scale(.25) 9 img.write('thumb.jpg') 10 end