1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】 Active Storage で S3 にファイルを保存・取得する

Posted at

概要

Rails でアプリケーションを作成するなかで、Active Storage を使用して S3 にファイルを保存・取得する処理を実装しました。
導入方法や使用した機能についてまとめます。

Active Storage とは

Rails ガイドに以下の記載があります。

Active Storage は、Amazon S3 や Google Cloud などのクラウドストレージサービスへのファイルのアップロードや、ファイルを Active Record オブジェクトにアタッチする機能を提供します。

つまり、S3 などに保存されているファイルと、DB テーブルのレコードを紐づけて管理する機能を提供するライブラリです。
後述しますが、レコードとの紐づけを行わずにファイルを管理することもできます。

導入手順

S3 のバケットはすでに作成されている前提で進めます。

環境を整える

Active Storage が S3 を使用できるように設定します。

  1. config/storage.yml のコメントアウトされている箇所を戻します

    config/storage.yml
    amazon:
      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"] %>
    
  2. 環境変数に以下を設定します
    基本的に AWS の管理画面のバケットの情報に記載がある内容をそのまま使用します

    .env
    AWS_ACCESS_KEY_ID=アクセスキー
    AWS_SECRET_ACCESS_KEY=シークレットアクセスキー
    AWS_REGION=AWSリージョンap-northeast-1 など
    AWS_BUCKET=バケット名
    
  3. Active Storage が S3 を使用するよう、development.rb を編集します
    ここでは development.rb を編集していますが、必要に応じて production.rb も編集します。
    なお、開発環境 で S3 を使用し続けると不要なファイルが溜まってコストが増えるので、動作確認ができたら:localに戻すようにしています。

    development.rb
    config.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 に保存する

レコードと紐づける

  1. User のモデルにhas_one_attached :任意のカラム名を追加

    class User < ApplicationRecord
        has_one_attached :avatar
    end
    

    これでレコード1件に対し、1個のファイル(avatar)を紐付けます。
    レコードとファイルを 1 対多で紐づけたい場合は、has_many_attachedを使用します。

  2. ファイルをレコードに紐づけ、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を設定すると、ダウンロードせず画像をそのまま表示します。

所感

簡単な操作であれば、僅かな記載で実装できて便利だと感じました。
複数のレコードとファイルが紐づいているので、ファイル削除のタイミングなどは気をつけないといけませんね。

参考文献

Rails ガイド

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?