概要
Rails でアプリケーションを作成するなかで、Active Storage を使用して S3 にファイルを保存・取得する処理を実装しました。
導入方法や使用した機能についてまとめます。
Active Storage とは
Rails ガイドに以下の記載があります。
Active Storage は、Amazon S3 や Google Cloud などのクラウドストレージサービスへのファイルのアップロードや、ファイルを Active Record オブジェクトにアタッチする機能を提供します。
つまり、S3 などに保存されているファイルと、DB テーブルのレコードを紐づけて管理する機能を提供するライブラリです。
後述しますが、レコードとの紐づけを行わずにファイルを管理することもできます。
導入手順
S3 のバケットはすでに作成されている前提で進めます。
環境を整える
Active Storage が S3 を使用できるように設定します。
-
config/storage.yml のコメントアウトされている箇所を戻します
config/storage.ymlamazon: service: S3 access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %> secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %> region: <%= ENV["AWS_REGION"] %> bucket: <%= ENV["AWS_BUCKET"] %> -
環境変数に以下を設定します
基本的に AWS の管理画面のバケットの情報に記載がある内容をそのまま使用します.envAWS_ACCESS_KEY_ID=アクセスキー AWS_SECRET_ACCESS_KEY=シークレットアクセスキー AWS_REGION=AWSリージョン(ap-northeast-1) など AWS_BUCKET=バケット名 -
Active Storage が S3 を使用するよう、development.rb を編集します
ここでは development.rb を編集していますが、必要に応じて production.rb も編集します。
なお、開発環境 で S3 を使用し続けると不要なファイルが溜まってコストが増えるので、動作確認ができたら:localに戻すようにしています。development.rbconfig.active_storage.service = :amazon
Active Storage をセットアップ
以下を実行するだけです。
$ bin/rails active_storage:install
$ bin/rails db:migrate
これを実行すると、Active Storage が利用するテーブルが3つ作成されます。
- active_storage_blobs
ファイルのメタ情報 - active_storage_attachments
どのレコードにどのファイルが紐づいているかの情報 - active_storage_variant_records
リサイズした画像などのバリアント情報
これで準備は完了です。
ファイルを保存・取得する
ここでは、users テーブルにアバター画像を紐づけることを目的とします。
ファイルを S3 に保存する
レコードと紐づける
-
User のモデルに
has_one_attached :任意のカラム名を追加class User < ApplicationRecord has_one_attached :avatar endこれでレコード1件に対し、1個のファイル(avatar)を紐付けます。
レコードとファイルを 1 対多で紐づけたい場合は、has_many_attachedを使用します。 -
ファイルをレコードに紐づけ、S3 に保存する
user.avatar.attach(params[:avatar])なんとこれだけです。
この記述だけでファイルは S3 に保存されて、User のレコードに紐づきます。
レコードと紐づけない
アプリケーションのモデル(User など)とは紐づけず、S3 にファイルを保存するだけ、ということも可能です。
image_file = params[:image]
filename = image_file.original_filename
key = "#{user.id}/#{DateTime.now.strftime("%Y%m%d%H%M%S")}/#{filename}"
ActiveStorage::Blob.create_and_upload!(
key: key,
io: image_file,
filename: filename,
content_type: image_file.content_type
)
この例では、画面からアップロードされたファイルを S3 に保存しています。
key を設定することで、パスを指定できます。
ファイルを S3 から取得する
user.avatar
これで該当のレコードに紐づくファイルのオブジェクトを取得できます。
ファイルを S3 から削除する
user.avatar.purge if user.avatar.attached?
purgeで active_storage_blobs、active_storage_attachments、active_storage_variant_records のレコード、S3 上のファイル本体が物理削除されます。
ここではattached?を使用し、avatar にファイルが紐づいている場合のみ削除するようにしています。
なお、purgeは即時削除されますが、purge_laterとすることでジョブで非同期削除することができます。
画像のダウンロードリンクを発行する
include Rails.application.routes.url_helpers
rails_blob_url(user.avatar, disposition: :attachment)
これでダウンロードリンクが発行できます。
disposition: :attachmentを設定することで、URL へアクセスしたタイミングでダウンロードさせます。
disposition: :inlineを設定すると、ダウンロードせず画像をそのまま表示します。
所感
簡単な操作であれば、僅かな記載で実装できて便利だと感じました。
複数のレコードとファイルが紐づいているので、ファイル削除のタイミングなどは気をつけないといけませんね。