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

aco*_*rth 8 download ruby-on-rails-3 carrierwave

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

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

这会抛出一个错误:
ResourcesController中的ActiveRecord :: RecordNotFound#show无法找到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
Run Code Online (Sandbox Code Playgroud)

我在routes.rb中设置了一条路由,如下所示:

  resources :resources do
    get 'resources', :on => :collection
  end
Run Code Online (Sandbox Code Playgroud)

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

我正在运行:Rails 3.2.11 Carrierwave 0.8.0 Ruby 1.9.3-p194

我希望对此有所了解.我搜索了很多文章,但却找不到简单的教程.谢谢.

aco*_*rth 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
Run Code Online (Sandbox Code Playgroud)

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

send_file接受许多其他参数,看起来是可选的,因为我只需要其中的三个.有关其他参数,请参阅API文档.

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

对于我的目的(下载而不是在浏览器中显示),真正重要的论点是:处理需要设置为"附件"而不是"内联".

另一个参数: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
Run Code Online (Sandbox Code Playgroud)

通过这些更改,我不再需要设置:type.设置":url_based_filename => 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
Run Code Online (Sandbox Code Playgroud)

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