文件从Carrierwave文档附件链接下载

时间:2013-03-10 19:52:03

标签: ruby-on-rails-3 download carrierwave

我尝试制作一个简单的链接,点击该链接会启动与特定资源相关联的文档的下载。我有一个资源模型,在该模型中有一个名为" document"的列。我可以在单击链接时成功查看文档内联,但我更愿意下载它。我一直在阅读有关内容类型和send_file的内容,但我还没有能够将它们完全拼凑起来以便运行。

以下是我认为我需要用于链接的代码:
<%= link_to 'Download File', :action => "download_file" %>

这会引发错误:
ResourcesController#show中的ActiveRecord :: RecordNotFound 无法找到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

因此基于此错误,似乎我在ResourcesController中的download_file方法无法确定与文档关联的资源记录的ID。

我正在跑步: Rails 3.2.11 Carrierwave 0.8.0 Ruby 1.9.3-p194

我很欣赏对此的一些见解。我搜索了很多文章,但却找不到简单的教程。感谢。

1 个答案:

答案 0 :(得分: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

在我的情况下,我在变量@resource中返回了一条记录,其中有一个与之关联的文档(同样,我正在使用Carrierwave)。所以send_file需要的第一个参数是路径(参见API for send_file)。此路径信息由@ resource.document.path提供。

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

其中一个为我抛出错误的是类型:我传递了变量“@ resource.file.content_type”,但它显然正在寻找文字。一旦我通过它application / pdf,它就有效了。如果没有明确设置,则下载的文件未添加文件扩展名。在任何情况下,对于我的应用程序,这个文档可能是各种不同的mime类型,从pdf到word到mp4。所以我不确定如何指定多个。

对于我的目的(下载而不是在浏览器中显示),真正重要的论点是:处置需要设置为'attachment'而不是'inline'。

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

我还需要将link_to标签更改为:
<%= link_to 'Download File', :action => 'download_file', :id => resource.id %>

请注意,提供具有当前资源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 =&gt; true”保持在URL中的记录ID之后命名文件。基于我对该参数的函数的读取,将此设置为false似乎是违反直觉的,但是,这样做会产生在实际文件名之后命名文件的期望结果。

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

require 'carrierwave/processing/mime_types'

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

这个gem显然设置了文件名中文件扩展名猜出的mime类型。这样做使我不必在我的download_file方法中的send_file参数中设置:显式类型。