Read more

Common mistakes when storing file uploads with Rails

Henning Koch
June 27, 2013Software engineer at makandra GmbH

1. Saving files to a directory that is not shared between deploys or servers

If you save your uploads to a made up directory like "RAILS_ROOT/uploads", this directory goes away after every deploy (since every release gets a new). Also this directory is not shared between multiple application servers, so your uploads are randomly saved to one local filesystem or another. Fixing this afterwards is a lot of fun.

Illustration money motivation

Opscomplete powered by makandra brand

Save money by migrating from AWS to our fully managed hosting in Germany.

  • Trusted by over 100 customers
  • Ready to use with Ruby, Node.js, PHP
  • Proactive management by operations experts
Read more Show archive.org snapshot

Only two folders are, by default, shared between our application servers and deployments: "RAILS_ROOT/storage" and "RAILS_ROOT/public/system" (note that this might be different if you are not hosting at makandra Show archive.org snapshot ).

2. Publishing confidential files to the whole Internet

All files in public/system are publicly accessible and requests will not touch your Rails application. Users can usually download your entire file catalog by seeing one path like "public/system/images/4.jpg" and then replacing the record ID (4) with values from 1 to 9999999999.

So don't store confidential stuff in there. Non-public files should by default go into /storage and should be delivered from a Rails controller action (e.g. /images/4/download) by using send_file. Since Rails code is doing the delivery you can do your usual authentication and authorization beforehand.

There are few exceptions where you want to store confidential files in the public folder. E.g. you need to deliver many thumbnails for an image gallery and don't want to spawn 50 Rails processes to deliver the image. In that case you can store the images in public/system but use for the path a non-guessable hash of e.g. the record ID and the application's secret token. So virtual paths need to look like "/public/system/images/5/ab4543fa3ecf44/image.jpg".

3. Using the same storage folder for multiple Rails environments or test processes

This one affects your developers. If an image with ID 4 always ends up as public/system/images/4.jpg, multiple Rails environments (e.g. development and test) will randomly see and overwrite each other's files. See Always store your Paperclip attachments in a separate folder per environment for instructions how to fix this in Paperclip. Apply similiar techniques to Carrierwave etc.

4. Ignoring existing files when changing your storage paths

When you change your applications (e.g. because you follow the advice in this post) you must migrate files that are already stored on your staging and production servers. If the application hasn't seen production yet, check with your client if you can simply wipe all images/documents/whatever. But don't display broken images, it's unprofessional und looks like you screwed up.

5. Rails 2: Forgetting to add the multipart option to your upload form

When uploading files, you must set the multipart option like this in very old versions of Rails:

form_for @invoice, :html => { :multipart => true } do

If you do not, Rails will only receive the file name.

Posted by Henning Koch to makandra dev (2013-06-27 11:24)