Question

I've created a file in the tmp directory with the following controller code:

  def download
    file_path = "#{RAILS_ROOT}/tmp/downloads/xxx.html"
    data = render_to_string( :action => :show, :layout => nil )
    File.open(file_path, "w"){|f| f << data }
    flash[:notice] = "saved to #{file_path}"
  end

This creates the file I wanted in the tmp directory, what I want to do is force the user to download that file.

On my local machine, the file is saved to path like:

/Users/xxxx/Documents/Sites/xxxx/Website/htdocs/tmp/downloads/xxxx.html

And on the live server this url will be somthing totally different.

What I was wondering is how do I force the user to download this xxxx.html ?

P.S. If I put a...

redirect_to file_path

...on the controller it just give's me a route not found.

Cheers.

Was it helpful?

Solution

Take a look at the send_file method. It'd look something like this:

send_file Rails.root.join('tmp', 'downloads', 'xxxxx.html'), :type => 'text/html', :disposition => 'attachment'

:disposition => 'attachment' will force the browser to download the file instead of rendering it. Set it to 'inline' if you want it to load in the browser. If nginx is in front of your Rails app then you will have to modify your environment config (ie. environments/production.rb):

# For nginx:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

OTHER TIPS

It's easy to confuse file paths with URLs, but it is an important distinction. What has a URL path of /a/b.txt is actually located in the system path #{Rails.root}/public/a/b.txt so you may need to address this by generating both in tandem.

Here's how you might address that:

def download
  base_path = "downloads/xxx.html"

  system_path = File.expand_path("public/#{base_path}", Rails.root)
  url_path = "/#{base_path}"

  File.open(file_path, "w") do |f|
    f.puts render_to_string(:action => :show, :layout => nil)
  end

  flash[:notice] = "saved to #{base_path}"

  redirect_to(url_path)
end

You cannot redirect to a resource that is not exposed through your web server, and generally only things in public/ are set this way. You can include additional paths if you configure your server accordingly.

You can also side-step this whole process by simply rendering the response as a downloadable inline attachment, if you prefer:

render(:action => :show, :layout => nil, :content_type=> 'application/octet-stream')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top