views:

364

answers:

4

Hi Folks,

I'm new to Rails and working on a project where after the user logs in they can click on a link to download an exe file ( say for example the file is at http://test.com/test.exe). I want to keep the link to the exe file hidden. What are the best ways to implement this step.

I was thinking about using the redirect to url but I have been getting an error saying that I cannot use two redirect's in a function.

Also, I was thinking of using NET:HTTP to use http request but I have no idea how to implement this.

Thanks!!

+1  A: 

You should read the file in your code and output it as-is to the client. Send before it the relevant headers:

Content-type: application/octet-stream  
Content-Disposition: inline; filename=[file name you want the user to see]  
Content-length: [file size]

Why doing two redirects in same place is bad, it is like trying to steer a car in two directions at once...

It might be better to use

Content-Type: application/force-download

instead of

Content-type: application/octet-stream
Itay Moav
but this file would be almost 1GB. I'm trying to let certain users download the software but want to keep the link to the software hidden, that way its not distributed to everyone.
Wow, 1 Gig is not for usual http, you will need to break it (use rar).My solution is what you need. You read the file in your code (server side, no user can see the file name or where it is) and you output it with a random name (see second header).
Itay Moav
Itay, thanks for the reply.Since I'm new to rails I'm trying to understand your post, lol. Could you point me to some code samples, thanks!
A: 

To proxy the file through your controller, you can use open-uri.

In environment.rb

require 'open-uri'

In your controller

def download
  send_data(open(params[:url]).read,
    :filename => 'somefilename',
    :disposition => 'attachment'
  )
end

EDIT: If you don't want to proxy the file, you have to redirect_to(url). If you're getting the message about redirect called twice, then keep in mind that you cannot both render and redirect from the same action. If you need to load a view, and then start a download, use two actions:

def present_download
  @download = Download.find(params[:id])
  # implicitly calls render :action => :present_download
end

def download_file
  @download = Download.find(params[:id])
  respond_to do |format|
    format.html { redirect_to(@download.url) }
  end
end

And in your view (present_download.html.erb):

<html>
  <head>
    <meta http-equiv="refresh" content="1;url=<%= url_for :action => :download_file -%>" />
  </head>
  <body>
    Your download will automatically start…
…
Sam C
Thanks for the post. Can I do the samething with send_file?I don't know in my original post I included this or not, the exe file is not on the same server where my rails application is running.
Also I noticed in your code snippet that you are reading the whole file (open.url.read), if the file is a 1GB file then?
No, send_file and send_data would both require reading the contents of the file, though send_file would be much more efficient if you had access to the disc containing the file from your Rails app.
Sam C
That worked, Thanks a lot!!!
A: 

I tried the below code, just an example exe file but the code looks like is reading the whole file which is over 500 MB. I want it to just give me the option to save the exe file Thanks!

  def download
    send_data(open('http://mirrors.gigenet.com/ubuntu/intrepid/ubuntu-8.10-desktop-i386.iso').read,
    :filename => 'ubuntu-8.10-desktop-i386.iso' ,
    :type => 'application/force-download',
    :disposition => 'attachment')
  end
A: 

Seems like no one has mentioned X-Sendfile.

File Downloads Done Right

Matt Haley