Generic File And Image Models For Uploaded Files
Join the DZone community and get the full member experience.
Join For FreeThese 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
# NOTE: File.basename doesn't work right with Windows paths on Unix
# get only the filename, not the whole path
filename.gsub! /^.*(\\|\/)/, ''
# Finally, replace all non alphanumeric, underscore or periods with underscore
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
end
Controller Usage:
# returns DbImage if content_type matches
db_file = DbFile.new_file(params[:file][:data])
db_file.save
Model Usage:
# raw binary image data
File.open('my_file', 'w') { |f| f.write(db_file.data) }
# Image resizing with rmagick
# automatically creates RMagick::Image and
# invokes GC.start
db_file.with_image do |img|
img.scale(.25)
img.write('thumb.jpg')
end
Opinions expressed by DZone contributors are their own.
Comments