3

我在 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 ?

PS如果我放一个...

redirect_to file_path

...在控制器上,它只是给了我一条找不到的路线。

干杯。

4

2 回答 2

4

看一下send_file方法。它看起来像这样:

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

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

# For nginx:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
于 2011-05-03T04:30:25.973 回答
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')
于 2011-05-02T20:35:38.310 回答