Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Just a little thingamajingy to do file uploads with progress in rails
JavaScript Ruby
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
app
config
db
doc
lib/tasks
public
script
spec
test
.gitignore
Gemfile
Gemfile.lock
README
Rakefile

README

The task:

Back-end Developer Challenge

Design and implement a system that will accept a multipart form upload
(say, containing an audio file) while displaying a percentage
progress.

The basic HTML design should look like:

Display form with file input field
Display a title text field
Display a status text paragraph "select file"
Optionally display a submit button

Specification:

When the user picks a file from their computer and the form is submitted, the
upload begins.
While uploading, the status text paragraph should be updating with the current
percentage complete at least once every 2 seconds.
While uploading, the user should be able to enter text into the title text field.

When the upload completes, the status text should display the path on the server
to the saved file, and the current value of the title text field should be
posted to the server. The response to the form post request should display both
the title and the path to the file.

Requirements:

The upload should honor proxy settings on the browser
The system must function behind a firewall that blocks all but port 80
The server must support at least 2 concurrent uploads from different users
Any technology that can be web deployed to IE, Firefox, Safari, Chrome
(iPad/iPhone is optional) on any platform is supported
--------------------------------------------------------------------------------

Homework:

There's a lot of file upload handling code and examples out there, especially for the frontend part.
Here's an incomplete list:

Flash based frontend libraries:

  * http://jimneath.org/2008/05/15/swfupload-paperclip-and-ruby-on-rails/
  * http://swfupload.org/
  * http://railstips.org/blog/archives/2009/07/21/uploadify-and-rails23/
  * http://www.uploadify.com/
  * http://www.plupload.com
  * http://digitarald.de/project/fancyupload/
  * http://developer.yahoo.com/yui/uploader/

A complete Perl solution:

  * http://uber-uploader.sourceforge.net

Here's a good list of non-flash options:

  * http://stackoverflow.com/questions/2714507/jquery-ajax-upload-with-progress-bar-no-flash

There are also two complete challenge solutions to be found:

  * https://github.com/rngtng/FileUploadProgress
  * https://github.com/betten/SoundCloud-Developer-Challenge

For the backend, there are some Java Based ones (there's one from the apache project), lots of PHP
hacks, and you could always roll your own.

Or, this:

  * http://github.com/drogus/apache-upload-progress-module

--------------------------------------------------------------------------------

Stack used:

  * Apache2
  * Passenger
  * REE 1.8.7
  * Rails 2.3.11
  * http://github.com/drogus/apache-upload-progress-module
  * http://html5boilerplate.com/
  * https://github.com/valums/file-uploader
  * A self-rolled Upload model

--------------------------------------------------------------------------------

Notes:

This fulfills the requirements as far as I can see (except on IE, see below).

Bonus features:

* Non-JS fallback
* Specs
* Error handling for JS version

Yes, well, Internet Explorer, how you hate me... The upload progress display doesn't work
in Internet Explorer (8), because the Ajax Uploader JS library doesn't support this. I
didn't realize this when starting out with it, and now I don't want to throw away half of the code
to try with another frontend lib. And I'm not good enough with JS to try to fix it myself in the
available time.

I've used the older Ruby/Rails versions because I'm most familiar with them, and
didn't have the time to dig into Rails 3 for this challenge.

The Apache upload progress module isn't technically necessary as the JS FileUploader
lib does a pretty good job of getting the progress right, but I had already built most
of the progress tracking before I realized that.

I created my own Upload model because I wanted to try out how well this would work,
and I was wary of any baggage a lib like Paperclip would bring. In a real app, there
would most likely be more requirements for the file handling and tracking which I can't guess,
which might make Paperclip a better choice. Plus, I didn't want to do a complete copy
of the other solution on Github...

I've built the non-JS upload version first to make sure I get the model/controller right,
and kept it as a fallback option (However unlikely a non-JS browser is these days).
Well, at least lynx users can also use the upload :)

I didn't do any frontend specs (i.e. JS/HTML checks) because those get quite messy
in my experience - one should use Selenium and/or a QA person to check things like that.

The pages look like crap - quite frankly I'm not good with CSS and layouts,
but prettyness wasn't a requirement ;)

All in all, I'm surprised that there is so much to be done to get a well-working
upload progress feature. Chrome already shows an upload percentage natively when using
the non-JS file upload, so hopefully browsers will eventually support this natively (like
HTTP authentication improved a lot lately).

--------------------------------------------------------------------------------

TODO:
  * -Cronjob to clean up old files-
  * -Deploy on a server-
  * Limit file size
  * Check in Apache config
  * Test with more browsers. Working:
  ** Ubuntu 10.04/Chrome 5.0.342.9 beta
  ** Ubuntu 10.04/Firefox 3.6.15
  ** Windows 7/Chrome 10
  ** Windows 7/Firefox 3.6.15
  ** Windows 7/Internet Explorer 8 - only upload works, progress display is not supported by ajax uploader lib
  ** Windows 7/Safari 5.0.4

-------------------------

Installation dependencies on vanilla system:

git-core
apache2
emacs
build-essential
zlib1g-dev
libssl-dev
libreadline5-dev
REE
libcurl4-openssl-dev
apache2-prefork-dev
libapr1-dev
libaprutil1-dev
Passenger
Something went wrong with that request. Please try again.