Let's start with the basics. Suppose you have an action like this:
def upload_to_meAssume that the_file is an item uploaded from a form in a file input field. Now Rails will automatically process all this for you and handle the temp file creation and all that. However one optimization Rails will do is if the file is smaller than 10kB, it just sticks it in an UploadedStringIO object which is not a file - so there is no temporary file.
file = params[:the_file]
Let's expand our action. We want to open up this file (assume it is a .zip) and take a peek at the contents:
Zip::ZipFile.open(file.path) do |zip|The ZipFile object only accepts a filename. There is no way for you to pass in anything else, like say an IO object. So we have a predicament. The UploadedStringIO object we have is raw zipped data, but we can't actually unzip it because it is not a file.
What's the solution? It's ugly, but turn it into a file:
if file.is_a?(UploadedStringIO)We use Ruby's Tempfile object, which stores things in a temporary folder (by default on Ubuntu it appears to be /tmp) and is designed to be thread-safe so that you don't have to worry about people clobbering each other's temp files.
temp_file = Tempfile.new("some_temp_name")
file = temp_file
# now file is a File object and can be treated as such
I suppose since I have access to both Rails' code and the Zip gem's code, I could probably hack this stuff to make it work properly without being ugly, but this small fix should be enough for now. A good optimization would be to add something to ZipFile so that it can accept a IO object and not just a filename.