Skip to content

How to: Upload from a string in Rails 3

Jarosław Kowalewski edited this page Mar 2, 2017 · 12 revisions

Rails 3 no longer provides a StringIO#original_filename method, so uploading files from a string doesn't work. For example, the following worked in Rails 2:

StringIO.new("foobar").original_filename # => "stringio.txt"

But in Rails 3, we see this error:

StringIO.new("foobar").original_filename NoMethodError: undefined method original_filename for StringIO

Quick and dirty solution:

StringIO.class_eval { def original_filename; "stringiohaxx.png"; end }

But, I'd much prefer not monkey patching the class in case another library is expecting it to behave as documented. To achieve this, I've most recently done something like the following in a config/initializers/stringiohax.rb file.

class AppSpecificStringIO < StringIO
  attr_accessor :filepath

  def initialize(*args)
    super(*args[1..-1])
    @filepath = args[0]
  end

  def original_filename
    File.basename(@filepath)
  end
end

You can then do the following (or something similar) in your Model:

class DropboxFile < ActiveRecord::Base
  mount_uploader :attachment, AttachmentUploader

  def download(dropbox_session)
    file_as_string = dropbox_session.download(path)
    self.attachment = AppSpecificStringIO.new(path, file_as_string)
  end
end

Also, there is another quick solution, more clear. We can use Ruby's singleton method:

def perform
  io = StringIO.new("foobar")

  def io.original_filename
    "export.pdf"
  end

  Task.create(file: io)
end
Clone this wiki locally