File upload with Sinatra

by Pandafox | Posted in Ruby, Tutorials

Handling file uploads in sinatra is, not surprisingly, really simple. In this short tutorial we’re going to implement a basic file uploader, capable of uploading any kind of files. But beware, no effort will be put into actually securing the application.

Required gems

Sinatra
HAML

The view

Let’s start by setting up our form (using HAML, because that’s what the cool kids are using):
File: views/upload.haml:

%html
  %body
    %h1 File uploader!
    %form(method="post" enctype='multipart/form-data')    
      %input(type='file' name='myfile')     
      %br
      %input(type='submit' value='Upload!')

Nothing fancy, but it’ll do for now.

Request handling

Now, let’s make our server handle the GET- and POST-requests coming from the client:
File: server.rb:

require 'rubygems'
require 'sinatra'
require 'haml' 

# Handle GET-request (Show the upload form)
get "/upload" do
  haml :upload
end       
   
# Handle POST-request (Receive and save the uploaded file)
post "/upload" do  
  File.open('uploads/' + params['myfile'][:filename], "w") do |f|
    f.write(params['myfile'][:tempfile].read) 
  end
  return "The file was successfully uploaded!"
end

As you can see, you don’t have to write much code to get this to work. The params-hash contains our uploaded element with data such as filename, type and the actual datafile, which can be accessed as a Tempfile-object. We read the contents from this file and store it into a directory called uploads, which you will have to create before running this script.

Here’s an example of what the params-hash may look like when uploading a picture of a cat:

{
  "myfile" => {
    :type => "image/png",
    :head =>  "Content-Disposition: form-data;
               name=\"myfile\";
               filename=\"cat.png\"\r\n
               Content-Type: image/png\r\n",
    :name => "myfile",
    :tempfile => #<File:/var/folders/3n/3asd/-Tmp-/RackMultipart201-1476-nfw2-0>,
    :filename=>"cat.png"
  }
}   

Beware!

This script offers little to no security at all. Clients will be able to overwrite old images, fill up your harddrive and so on. So just use some common sense and do some Ruby magic to patch up the security holes yourself.

The result

Here’s a short video demonstrating what you should end up with after following this tutorial: