我已经在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 ?
注:如果我放一个…
redirect_to file_path
…在控制器上,它只是给我一个没有找到的路由。
欢呼。
看一下send_file方法。它看起来像这样:
send_file Rails.root.join('tmp', 'downloads', 'xxxxx.html'), :type => 'text/html', :disposition => 'attachment'
:disposition => 'attachment'将强制浏览器下载文件而不是呈现它。如果你想让它在浏览器中加载,就把它设为'inline'。如果nginx是在你的Rails应用程序的前面,那么你将不得不修改你的环境配置(即。环境/production.rb):
# For nginx:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
很容易将文件路径与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')