Rails StringIO File Upload
# UPDATE
It turns out the method below works unless your file is below a certain file size (which I haven’t figured out yet but it’s around 15k). If your file is too small it will be StringIO not a Tempfile. So how do we check it then? By the file size, if it’s 0 then don’t run the image upload code.
Replace
with
# END UPDATE
Coming from PHP getting file uploads to work with Rails was a bit of a mind funk.
The biggest issue is that a file upload field returns different objects depending on if you browsed for a file or left it blank. If you browsed and chose a file the object will be a ‘Tempfile’, if it’s blank it will be ‘StringIO’. That took a couple of hours to figure out.
The next step was figuring out how to check the object type, that’s when I stumbled upon some beauty Ruby code
object.kind_of?
Simple once you know how.
The file field from the form in my view:
Here’s my controller code for updating data from the form (the controller is products_controller.rb so I’m setting a relationship to the Image ‘product_id’):
def update #save image
params[:image][:product_id] = params[:id]
#upload it unless it's StringIO
@image = Image.create params[:image] unless params[:image][:file_data].kind_of? StringIO #save product params
@product = Product.find(params[:id])
#update params that have changed
if @product.update_attributes(params[:product])
#flash and redirect
flash[:notice] = 'Product was successfully updated.' redirect_to :controller => 'cms', :action => 'index' else render :action => 'edit' end end
The line to notice is
It translates to; save the image model unless file_data is a StringIO object (if it’s not StringIO then it’s a Tempfile)




Like this post? subscribe to the feed.




This post helped me out more than you know.
I’m not sure why file uploading in Rails is such a black-box area filled with weird special cases, but it’s nice to know I wasn’t the only one with the problem.
Comment by Adam T. — November 26, 2006 @ 10:29 pm
Definitely a big help. I was having trouble getting firefox tell whether a file was really being uploaded, and this was the path…thanks!
Comment by ira S. — December 3, 2006 @ 7:22 pm
i also encountered the same problem as you, but you could try
@image = Image.create params[:image] unless params[:image][:file_data].size == 0
there are .size method for both StringIO and TempFile, and it return zero if it is empty
Comment by chiamingen — February 22, 2007 @ 11:58 pm
If you’re file is small, you get a StringIO object. So only saving if you don’t have StringIO will not save small files.
Comment by Bart — March 14, 2007 @ 10:51 pm
Like Bart said, I am having that problem now. Some files actually come across as StringIO. I don’t know if it is based on the File Type or the Size of the file, but I can’t figure out how to get it back as a file object.
Comment by Tom — May 2, 2007 @ 12:26 pm
It is indeed the case that small files are StringIO objects while larger files get passed as a Tempfile object. This is done for performance reasons (small files can be kept in the buffer since they don’t take up too much space there, this saves us from filesystem operations which always carry some overhead (disk seek and the like)).
A universal way to process the uploaded data is:
File.open(”your/file/goes/here”, “wb”) { |f| f.write(params[:your_file_form_field].read) }
No matter whether you are working with a Tempfile or StringIO object, the CGI handler always provides params[:your_file_form_field].original_filename and .content_type for your processing pleasure.
Comment by Niels — July 22, 2007 @ 8:36 am
Thanks a lot Niels! That’s exactly what I needed. I couldn’t figure out for the life of me how to deal with small files that come in as StringIO objects.
Comment by Eric — October 2, 2007 @ 10:05 am
[...] http://blog.vixiom.com/2006/07/26/rails-stringio-file-upload/ [...]
Pingback by Rails and file uploads « 41 technologies — April 9, 2008 @ 10:05 pm
Thanks a lot.
What i had to add was a nil check, cause it throwed an exception when accessing the ’size’ property.
params[:image][:file_data].nil?
cheers
daniel
Comment by Daniel — February 26, 2009 @ 3:41 pm