These are basic models that store a file in a dedicated files table. Use has_one or has_many to associate this with your actual models. RMagick is required for images.
This is my first code dealing with uploads and rmagick, so please comment if you have suggestions.
class DbFile < ActiveRecord::Base
IMAGE_TYPES = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png']
before_validation :sanitize_filename
validates_presence_of :size, :filename, :content_type
class << self
def new_file(file_data)
content_type = file_data.content_type.strip
(IMAGE_TYPES.include?(content_type) ? DbImage : DbFile).new \
:data => file_data.read,
:filename => file_data.original_filename,
:size => file_data.size,
:content_type => content_type
end
end
protected
def sanitize_filename
filename.gsub! /^.*(\\|\/)/, ''
filename.gsub! /[^\w\.\-]/, '_'
end
end
require 'rmagick'
require 'base64'
class DbImage < DbFile
def data=(file_data)
with_image(file_data, true) do |img|
self.width = img.columns
self.height = img.rows
end
end
def with_image(file_data = nil, save_image = false, &block)
img = Magick::Image::read_inline(Base64.b64encode(file_data || self.data)).first
block.call(img)
write_attribute('data', img.to_blob) if save_image
img = nil
GC.start
end
endController Usage:
db_file = DbFile.new_file(params[:file][:data])
db_file.save
Model Usage:
File.open('my_file', 'w') { |f| f.write(db_file.data) }
db_file.with_image do |img|
img.scale(.25)
img.write('thumb.jpg')
end