2013-03-10 69 views
8

我试图做一个简单的链接,点击时启动与特定资源关联的文档的下载。我有一个资源模型,在该模型中有一个名为“文档”的列。点击链接时,我可以成功查看内联文档,但我更愿意下载它。我一直在阅读有关内容类型和send_file的内容,但是我一直无法完全将它组合在一起以实现功能。从Carrierwave文档附件的链接下载文件

这里是我想我需要使用的链接代码:
<%= link_to 'Download File', :action => "download_file" %>

这将引发一个错误:
的ActiveRecord :: RecordNotFound在ResourcesController#秀 可能找不到ID资源= download_file

当我更改链接到这一点,它会打开浏览器中的文件:
<%= link_to 'Open file', resource.document_url, :target => "_blank" %>

在我ResourcesController我已经定义了这个方法:

def download_file 
    @resource = Resource.find(params[:id]) 
    send_file(@resource.file.path, 
     :filename => @resource.file.name, 
     :type => @resource.file.content_type, 
     :disposition => 'attachment', 
     :url_based_filename => true) 
    end 

我在routes.rb中设置了这样的路线:

resources :resources do 
    get 'resources', :on => :collection 
    end 

所以基于这个错误,它似乎是我的download_file方法在ResourcesController中无法确定与该文档相关联的资源记录的ID。

我运行: 的Rails 3.2.11 Carrierwave 0.8.0 的Ruby 1.9.3-P194

我希望得到一些洞察到这一点。我搜查了一些文章,但无法找到简单的教程。谢谢。

+0

非常感谢。这一切都创造了奇迹。 Rails 4 - CarrierWave。 – 2015-01-27 03:17:06

回答

13

我能弄明白这一点。我会试图解释我是如何解决这个问题的。

download_file方法正确地位于ResourcesController中,但我没有使用正确的变量名称。这是我的目的,正确的方法定义:

def download_file 
    @resource = Resource.find(params[:id]) 
    send_file(@resource.document.path, 
     :type => 'application/pdf', 
     :disposition => 'attachment', 
     :url_based_filename => true) 
    end 

在我来说,我有一个记录在具有与它相关联(同样,我使用Carrierwave)文档变量@resource返回。所以send_file要求的第一个参数是路径(请参阅API for send_file)。此路径信息由@ resource.document.path提供。

send_file需要许多其他参数,这似乎是可选的,因为我只需要其中的三个。有关其他参数,请参阅API文档。

其中一个引发错误的是我的类型:.我将变量“@ resource.file.content_type”传递给它,但显然它正在寻找文字。一旦我通过它的应用程序/ pdf,它的工作。如果没有明确设置这个,下载的文件没有添加文件扩展名。无论如何,对于我的应用程序来说,这个文档可以是从pdf到word到mp4的各种不同的MIME类型。所以我不知道如何指定多个。

我的目的(下载而不是显示在浏览器中)的真正重要的论点是:需要设置为“附件”而不是“内联”的处置。

另一个参数:url_based_filename显然用于从URL中确定文件的名称。由于我没有提供文件名,也许这是我提供文件到被下载文件的唯一方式,但我不确定这一点。

我还需要到的link_to标签改成这样:
<%= link_to 'Download File', :action => 'download_file', :id => resource.id %>

需要注意的是供应:当前资源的ID符号提供识别有问题的资源所需的特定信息。

我希望这可以帮助别人。对于其他人来说,这一点非常明显,因为我没有找到关于文件下载文件的基本教程。我仍然在学习很多东西。

更新:我不得不玩弄这个来获得所需的行为。这里是正在工作的新方法:

 def download_file 
     @resource = Resource.find(params[:id]) 
     send_file(@resource.document.path, 
       :disposition => 'attachment', 
       :url_based_filename => false) 
     end 

通过这些更改,我不再需要设置:type。设置“:url_based_filename => true”会在URL中的记录标识之后继续命名文件。根据我对这个参数的函数的阅读,将这个设置为false似乎是违反直觉的,但是,这样做会产生在实际文件名后命名文件的理想结果。

我还使用了mime-types gem并添加以下到我的video_uploader.rb文件:

require 'carrierwave/processing/mime_types' 

class VideoUploader < CarrierWave::Uploader::Base 
include CarrierWave::MimeTypes 
process :set_content_type 

这种宝石显然设置MIME类型在文件名中的文件扩展名猜测。这样做使我不必设置:显式地在我的download_file方法内的send_file参数中输入。

+0

感谢您的信息! – tkrajcar 2013-10-19 18:47:10

+0

我使用Carrierwave gem,当我下载文件时,如果该文件名包含空格,那么它将转换为下划线。那么如何在下载时从文件名中删除下划线? – 2016-03-30 10:39:48