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

@image = Image.create params[:image] unless params[:image][:file_data].kind_of? StringIO

with

@image = Image.create params[:image] unless params[:image][:file_data].size == 0

# 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:

<%= file_field(“image”, “file_data”) %>

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

    @image = Image.create params[:image] unless params[:image][:file_data].kind_of? StringIO

It translates to; save the image model unless file_data is a StringIO object (if it’s not StringIO then it’s a Tempfile)

8 Responses to “Rails StringIO File Upload”

  1. Adam T. Says:

    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.

  2. ira S. Says:

    Definitely a big help. I was having trouble getting firefox tell whether a file was really being uploaded, and this was the path…thanks!

  3. chiamingen Says:

    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

  4. Bart Says:

    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.

  5. Tom Says:

    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.

  6. Niels Says:

    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.

  7. Eric Says:

    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.

  8. Rails and file uploads « 41 technologies Says:

    […] http://blog.vixiom.com/2006/07/26/rails-stringio-file-upload/ […]

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture.
Anti-Spam Image