File Uploading with Ruby

Here’s how to get a file from the user to rails.

Note: ruby’s CGI.rb accepts the multipart/form and saves the file to your /tmp directory.

Rather than load and save the file again, we’re just going to copy it from /tmp. simple? not necessarily. Sometimes the permissions don’t get set properly during uploading. Don’t know why. Just to make sure, we’re gonna set permissions at every possible stage!

This code is found in your photo model and is called like:
photo.uploaded_file = @params[‘file’]
.. where @params[‘file’] is the <input type=”file” name=”file” /> in your form. your photo records should contain a field, ‘content_type’, and ‘name’.

For bonus points, you can make your own filename sanitizer! MS-IE does a funny thing with filenames, which ruby’s CGI.rb should really fix, but doesn’t, so you’ll want to use File.basename in there somewhere.

def uploaded_file=(incoming_file)
self.name = sanitize_filename(incoming_file.original_filename)
self.content_type = incoming_file.content_type

# in theory, you could check content-type
# here to prevent malicous
# or unwanted file types.

@file = incoming_file

# screw you cgi.rb!
File.chmod(0600, incoming_file.local_path)

# you probably don’t want to
# upload to your public dir
# straight out..

# check if the file already exists?
if !File.exist?(RAILS_ROOT+”/public/pictures/”+self.name)
# make sure the tmp file exists.
# it will not exist if the file
# is under 10k in size,
# or if some othjer error occurred.

if !incoming_file.local_path.nil? && File.exist?(incoming_file.local_path)
FileUtils.copy(incoming_file.local_path, RAILS_ROOT+”/public/pictures/” + self.name)
else
# file didn’t exist locally? so,
# let’s try just writing it
# from our CGI memory.
File.open(“#{RAILS_ROOT}/public/pictures/#{self.name}”, “wb”) { |f| f.write(@file.read) }
end
else
999.times do |i|
if !File.exist?(RAILS_ROOT + “public/pictures/” + self.name + i.to_s)
self.name = self.name + i.to_s

if !incoming_file.local_path.nil? && File.exist?(incoming_file.local_path)
FileUtils.copy incoming_file.local_path, “#{RAILS_ROOT}/public/pictures/” + self.name
else
File.open(“#{RAILS_ROOT}/public/pictures/#{self.name}”, “wb”) { |f| f.write(@file.read) }

end
File.chmod(0664, “#{RAILS_ROOT}/public/pictures/#{self.name}”)
break

end
end
end
#create_thumbnail
end