0

I have what i imagine is a fairly common setup.

My rails 3 app is hosted on Heroku, and i use Paperclip to manage file uploading, of videos and images, with all files saved on Amazon S3. The model that the files are attached to is Entry, and the attachments themselves are called 'media'. So, I have paperclip set up like this:

class Entry < ActiveRecord::Base
  has_attached_file :media, {:storage=>:s3,
                             :bucket=>"mybucketname",
                             :s3_credentials=> <credentials hash>}

This is all working fine. But, I now want to add download links to the files, so the user can download the videos for editing for example. I've done this as follows:

Download link on the page:

<p><%= link_to "Download", download_entry_path(entry) %></p>

This just calls a download action in EntriesController which looks like this:

def download
  @entry = Entry.find(params[:id])
  if @entry.media.file?
    send_file @entry.media.to_file, :type => @entry.media_content_type, 
                                    :disposition => 'attachment', 
                                    :filename => @entry.media_file_name,
                                    :x_sendfile => true
  else
    flash[:notice] = "Sorry, there was a problem downloading this file"
    redirect_to report_path(@entry.report) and return      
  end  
end

Since some of the downloads will be very large, i'd like to hive the download off to the server to avoid tying up a dyno. That's why i'm using the x_sendfile option. However, i don't think it's set up properly: in the heroku log i can see this:

2011-06-30T11:57:33+00:00 app[web.1]: X-Accel-Mapping header missing
2011-06-30T11:57:33+00:00 app[web.1]: 
2011-06-30T11:57:33+00:00 app[web.1]: Started GET "/entries/7/download" for 77.89.149.137 at 2011-06-30 04:57:33 -0700
2011-06-30T11:57:33+00:00 app[web.1]: ### params = {"action"=>"download", "controller"=>"entries", "id"=>"7"}
2011-06-30T11:57:33+00:00 heroku[router]: GET <my-app>/entries/7/download dyno=web.1 queue=0 wait=0ms service=438ms status=200 bytes=94741

The "X-Accel-Mapping header missing" message suggests that something's not right, but i don't know what. Basically i don't know if heroku's nginx server takes on file downloading automatically, and if not then how to tell it to, and i can't find anything in heroku's documentation about it (i might be looking for the wrong thing).

Can anyone set me straight? Grateful for any advice - max

Max Williams
  • 32,435
  • 31
  • 130
  • 197

1 Answers1

3

I'm not sure why you're sending files via the server. If they're stored on S3, why not just link right to them?

<%= link_to "Download", entry.media.url %>

That way the downloads bypass your Heroku server altogether.

Frankie Roberto
  • 1,349
  • 9
  • 9
  • 1
    Hi Frankie. The reason i have it going through the controller is that at some point i'll need to make the s3 bucket private, so that it can only be accessed by the app. Then, people won't be able to right click (or click a link as you suggest) and open the file directly from its s3 url. Basically i need to keep control over who is allowed to download the files. – Max Williams Jun 30 '11 at 13:04
  • 1
    @Max, You can request S3 for a timeoutable download URL to your file that is in your private bucket. See http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html . Ruby libraries, such as Fog and Carrierwave, have builtin support for authenticated URLs. – randomguy Jul 12 '11 at 09:53