記事を書こうと思った理由
- ある日、RailsでS3からダウンロードの処理を書こうとした際、「あれ?そういえば、S3からのダウンロードってどうやってやるだっけ?」って調べたところ、S3へのアップロードの記事は多く見つけたけど、S3からダウンロードの記事が少ないと思い、せっかくなら記事にしちゃえ!と思いました。
準備するもの
- 前提として、S3へのアップロードができるアプリ
- S3へのアップロードのやり方が書かれてある記事は多くあるので、詳しい設定などは省きます。
- 開発環境
- Ruby 2.4.3
- Ruby on Rails 5.1.4
- Amazon S3にすでにアップロードされている画像
開発手順
それでは、コードを書いていきます。
1. downloadアクションのルート定義
プライマリーキーが必要になるので、 collection
ではなくmember
ですね。
routes.rb
resources :shared_files, only: %i(create destroy) do
member do
get :download
end
end
$ bundle exec rake routes | grep download
下のように、pathが生成されていることを確認したら、次に行きましょう。
download_shared_file GET /shared_files/:id/download(.:format) shared_files#download
2. view
button_to
は、 method
オプションがデフォルトで post
になるので、 しっかりと { method: :get }
とmethod
オプションの値を定義しましょう。
shared_files/index.html.slim
.shared-files__file-buttons
button.shared-files__file-download-button
= button_to 'ダウンロード', download_shared_file_path(shared_file), { method: :get }
3. モデル
モデルに少々メソッドを定義しましょう。環境変数は適宜定義していただけると幸いです。
shared_file.rb
class SharedFile < ApplicationRecord
AMAZON_S3_DOMAIN = "https://#{ENV['AWS_HOST_NAME']}"
mount_uploader :name, SharedFileUploader
def file_url
"#{AMAZON_S3_DOMAIN}/#{ENV['AWS_S3_DEV_BUCKET']}/#{self.file_name}"
end
def file_name
self.name.file.filename
end
def content_type
self.name.content_type
end
end
4.controller
- いよいよコントローラーの実装に入ります。
- この
data.read
の処理を探すのに、結構時間がかかりました。 - 仕様を読んだり、プロダクトマネージャーに確認をとったところ、日本語がリンクに含まれることから、
URI.encode
でエンコードします。 - ポイントは、
disposition: 'attachment'
と、 ファイルの種類をtype:
オプションで指定すること。disposition
キーにはデフォルトでattachment
設定されていますが、明記しました。type
でしっかりファイルの種類を指定してあげないと、全部jpeg
としてダウンロードされてしまいます。 -
send_data
のドキュメント ↓ - http://railsdoc.com/references/send_data
shared_files_controller.rb
class SharedFilesController < ApplicationController
def index
@shared_files = SharedFile.all
end
def download
@shared_file = SharedFile.find(params[:id)
data = open(URI.encode(@shared_file.file_url))
send_data data.read, disposition: 'attachment',
filename: @shared_file.file_name, type: @shared_file.content_type
end
end
これでダウンロード処理の完成です!お疲れ様でした。
まとめ
- 今回のような「あれ?この処理ってどうやって書くんだっけ?」と思うことは、すぐ記事にまとめてアウトプットしていきます!
- 自分は上のように書きましたが、もっといいやり方があればコメントに残していただけると幸いです。
参考にした記事