Ruby on Rails,强制用户下载临时文件

4

我已经在tmp目录中创建了一个文件,并使用以下控制器代码:

  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

这样就在tmp目录下创建了我想要的文件,我想做的是强制用户下载该文件。

在我的本地机器上,文件保存的路径类似于:

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

在实际服务器上,该URL将是完全不同的。

我想知道如何强制用户下载这个xxxx.html文件?

P.S. 如果我放置一个...

redirect_to file_path

当我在控制器上时,它只显示找不到路由的错误。

谢谢。

2个回答

5

请查看send_file方法。代码大致如下:

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

:disposition => 'attachment' 强制浏览器下载文件而不是渲染。如果您希望在浏览器中加载,请将其设置为“inline”。如果nginx在Rails应用程序之前,则必须修改环境配置(即environments/production.rb):

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

3

很容易将文件路径与URL混淆,但这是一个重要的区别。具有URL路径/a/b.txt实际上位于系统路径#{Rails.root}/public/a/b.txt中,因此您可能需要同时生成两者。

下面是解决方法:

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

您无法重定向到未通过您的Web服务器公开的资源,通常只有在public/中的内容才被这样设置。如果您配置了服务器,则可以包括其他路径。

如果您愿意,您还可以通过将响应呈现为可下载的内联附件来绕过整个过程:

render(:action => :show, :layout => nil, :content_type=> 'application/octet-stream')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接