今回することとしては、S3へアップロードしたファイルをダウンロードすることです。
実装の経緯としては、「ファイルをまとまった所にアップロードして共有し、そのファイルをいつでもダウンロードできるようにしたい」といった要望があったためです。
ファイルのアップロード自体は、何度が実装したことがあったのですが、よくよく考えると「S3側からダウンロードさせる」ことはしたことがないことに気づきました。まだまだ理解が乏しく参考になるかわかりませんが、同じような実装をしようとしている方の参考に少しでもなればと思います。
※S3へのファイルアップロードは、他にも参考記事がたくさんあるので省略します。当該記事では、carrierwaveを使用しS3へアップロードしています。
参考URL:https://qiita.com/junara/items/1899f23c091bcee3b058
##実装方法
実装方法としては、S3のpathを指定してsend_dataでダウンロードする方法です。
def download
file = params[:download_file]
file_id = params[:download_id]
# ファイルネームをエンコード(日本語のファイルに対応させるため)
file_name = ERB::Util.url_encode(file)
# data = open("https://[エンドポイント名]/[バケット名]/[ディレクトリ名]/[ファイル名]")
data = open("https://s3-ap-northeast-1.amazonaws.com/sample-bucket/uploads/upload/file/#{file_id}/#{file_name}")
send_data data.read, filename: file_name, disposition: 'attachment', stream: 'true', buffer_size: '4096'
end
※上記の場合、/uploads/upload/file/
の箇所がディレクトリ名となります。
viewのほうで、ダウンロードリンクを設置します。この際、download_idとdownload_fileのような形でパラメータをコントローラー側へ渡します。
- @downloads.each do |download|
- download.uploads.each do |upload|
= link_to upload[:file], download_path(download, download_id: upload[:id].to_s, download_file: upload[:file]) if upload[:file].present?
##はまった点
・下記の実装では、send_fileで行なっています。S3の場合は、ファイルデータの保持の仕方が違うのかsend_fileのpath指定をしてもダウンロードをすることができませんでした。S3ではなくサーバーに直接アップロードした場合できるかもしれません。(確認していません・・・ローカルでは確認済み)
file = params[:download_file]
file_id = params[:download_id]
file_name = ERB::Util.url_encode(file)
# ここまではS3の方法と同じ。
filepath = Rails.root.join('public/uploads/upload/file/'+ file_id, file_name)
send_file(filepath)
参考URL:https://qiita.com/akkun_choi/items/64080a8e17930879b4da
・AWS SDKを利用した方法では、ブラウザ上でダウンロードされず、実行しているプロジェクトのディレクトリ下にファイルがダウンロードされていました(「S3 ファイルダウンロード」で検索すると大抵「AWS SDK」の記事がでてくる)。そもそも今回しようとしていたブラウザ上でダウンロードする形に至らなかったため使用を断念。
##まとめ
今回なんとか求めていたファイルダウンロードを実装することができたが、まだまだ理解が乏しく無理やり実装した感が否めません・・・上記について、間違いやベストな方法がわかったら適宜更新していきたいと思います。