この前は、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
画像アップロードのために必要な設定を行います。
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を編集します。
CarrierWaveでは、asset_hostがあったのでブラウザから参照する際はパスを変更していたのですが、類似する設定が見つけられなかったので
http://minio:9000
でアクセスできるようにhostsを編集します。
# Add for practice 127.0.0.1 minio
環境は下記のような状態です。
新規登録画面
確認画面
登録後の詳細画面
MinIOにもアップロードされてます。(配置場所は、バケットの直下です。)
storage.ymlに以下を追加します。
regionがないと本番環境で動かす際に下記のエラーになったので注意してください。amazon: service: S3 bucket: mybucket-tlog-test force_path_style: true region: 'ap-northeast-1'
=== 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' 以下略
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に移行するにはひと手間加える必要がありそうです。(今後実装される?・・・
参考