8

クリックすると、特定のリソースに関連付けられたドキュメントのダウンロードが開始される単純なリンクを作成しようとしています。リソース モデルがあり、そのモデルには「ドキュメント」という列があります。リンクをクリックすると、ドキュメントをインラインで正常に表示できますが、ダウンロードしたいと思います。content-types と send_file について読んできましたが、これを完全につなぎ合わせて機能させることはできませんでした。

リンクに使用する必要があると思われるコードは次のとおりです。
<%= link_to 'Download File', :action => "download_file" %>

これによりエラーがスローされます:
ActiveRecord::RecordNotFound in ResourcesController#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

次のように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

これについての洞察をいただければ幸いです。いくつかの記事を検索しましたが、簡単なチュートリアルを見つけることができませんでした。ありがとう。

4

1 に答える 1

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 が必要とする最初の引数はパスです ( send_file の API を参照してください)。このパス情報は、@resource.document.path によって提供されます。

send_file は他にもいくつかの引数を取りますが、必要な引数は 3 つだけだったのでオプションのようです。その他の引数については、API ドキュメントを参照してください。

私のためにエラーをスローしていたものの1つはタイプでした:. 変数「@resource.file.content_type」を渡していましたが、明らかにリテラルを探していました。application/pdf を渡すと、うまくいきました。これを明示的に設定しないと、ダウンロードされるファイルにファイル拡張子が追加されません。いずれにせよ、私のアプリの場合、このドキュメントは、pdf から word、mp4 まで、さまざまな MIME タイプになる可能性があります。そのため、複数を指定する方法がわかりません。

私の目的 (ブラウザーに表示する代わりにダウンロードする) にとって本当に重要な引数は、「インライン」ではなく「添付ファイル」に設定する必要がある :disposition です。

もう 1 つの引数 :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 => 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 引数で :type を明示的に設定する必要がなくなりました。

于 2013-03-10T21:35:17.597 に答える