Log目次

【Rails】Active Storage + MinIO(S3)環境での画像アップロード処理

作成日 2019-09-05更新日 2019-09-05

はじめに

この前は、CarrierWave + MinIO(S3)の構成で画像のアップロード処理を作成しました。

今回はRailsのActive Storageを使用して同様のことを行いたいと思います。

※Active Storageの使い方に関しては深く掘り下げません。

完成したソースコードはこちら

インストール

Gemfileに以下を追加します。

gem "aws-sdk-s3", require: false

次にActive Storageのインストールを行います

rails active_storage:install

# This migration comes from active_storage (originally 20170806125915) class CreateActiveStorageTables < ActiveRecord::Migration[5.2] def change create_table :active_storage_blobs do |t| t.string :key, null: false t.string :filename, null: false t.string :content_type t.text :metadata t.bigint :byte_size, null: false t.string :checksum, null: false t.datetime :created_at, null: false t.index [ :key ], unique: true end create_table :active_storage_attachments do |t| t.string :name, null: false t.references :record, null: false, polymorphic: true, index: false t.references :blob, null: false t.datetime :created_at, null: false t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true t.foreign_key :active_storage_blobs, column: :blob_id end end end

MinIOに画像をアップロードするための設定

画像アップロードのために必要な設定を行います。

config/storage.ymlの設定

Active Storageの設定ファイルの編集を行います。

test: service: Disk root: <%= Rails.root.join("tmp/storage") %> local: service: S3 access_key_id: 'minio_access_key' secret_access_key: 'minio_secret_key' region: 'ap-northeast-1' endpoint: 'http://minio:9000' bucket: mybucket force_path_style: true

動作確認用のテーブル追加

active_strage_practicesという動作確認用のテーブルを追加します。

create_table :active_strage_practices do |t| t.string :name t.timestamps end

モデルの作成

以下のようにモデルを作成します。

class ActiveStragePractice < ApplicationRecord has_one_attached :avatar validates :name, presence: true attr_accessor :avatar_blob_id end

has_one_attached :avatarでActive Storageの関連テーブルと紐づけています。

avatar_blob_idはキャッシュ用に追加してます。

※Active Storage にはCarrierWaveにあったXXXX_cacheがないので独自で実装します。

確認画面で画像を表示するときに、direct_uploadした画像のblob_idを保持しておきコントローラー側でcreateする際に保持していたblob_idでActiveStorage::Blobの対象データを取得、対象のデータにattachしてます。

hostsの編集

ブラウザで画像を参照できるようにするためにhostsを編集します。

CarrierWaveでは、asset_hostがあったのでブラウザから参照する際はパスを変更していたのですが、類似する設定が見つけられなかったので

http://minio:9000

でアクセスできるようにhostsを編集します。

# Add for practice 127.0.0.1 minio

環境は下記のような状態です。

動作確認

新規登録画面

確認画面

登録後の詳細画面

MinIOにもアップロードされてます。(配置場所は、バケットの直下です。)

AWSにデプロイして確認してみる

Rails側の設定

storage.ymlに以下を追加します。

amazon: service: S3 bucket: mybucket-tlog-test force_path_style: true region: 'ap-northeast-1'
regionがないと本番環境で動かす際に下記のエラーになったので注意してください。
=== puma startup: 2019-09-01 15:12:20 +0000 === NoMethodError: Cannot load `Rails.config.active_storage.service`: undefined method `match' for nil:NilClass /home/ec2-user/test-deploy/shared/bundle/ruby/2.5.0/gems/aws-partitions-1.206.0/lib/aws-partitions/endpoint_provider.rb:82:in `block in partition_matching_region' /home/ec2-user/test-deploy/shared/bundle/ruby/2.5.0/gems/aws-partitions-1.206.0/lib/aws-partitions/endpoint_provider.rb:81:in `each' /home/ec2-user/test-deploy/shared/bundle/ruby/2.5.0/gems/aws-partitions-1.206.0/lib/aws-partitions/endpoint_provider.rb:81:in `find' 以下略

S3のCORS設定

mybucket-tlog-testバケットに初期状態では、何も設定されていないので下記のように設定します。

これを行わないとSignatureDoesNotMatchとなり、Active Storageのdirect_uploadが行えませんでした。
<?xml version="1.0" encoding="UTF-8"?> <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <MaxAgeSeconds>3000</MaxAgeSeconds> <AllowedHeader>Authorization</AllowedHeader> </CORSRule> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration>

動作確認

新規登録

確認画面

登録後の詳細画面

S3のバケット(選択中のものがアップロードしたものです。)

まとめ

無事、Active Storageを使用して、バケットへの画像のアップロードができました。

CarrierWaveにあったキャッシュ機能がなかったので、実装するのが少々手間でした。

また、ファイル形式に関するバリデーションなど既存の画像アップロード関連のGemが持つ機能がないみたいなのでActive Storageに移行するにはひと手間加える必要がありそうです。(今後実装される?・・・

参考