はじめに
Rails6の新機能「ActionText」はお手軽にリッチテキストエディターが利用できます。
ActionTextでアップロードした画像の保存先は、デフォルトではローカル(本番環境ならサーバー上)になっています。Railsアプリのデプロイ先としてHerokuを使うことが多いと思いますが、Herokuは定周期でデプロイ時の状態に戻していまいますので、デプロイ後にActionTextでアップロードした画像は時間が経つと消えてしまいます。
そこで、ActionTextでアップロードした画像の保存先をローカルから外部のクラウドストレージ(今回はAmazon S3)に変更したいのですが、うまくいきませんでした😥
現時点までに試した手順を備忘として残しておきます。もし、解決方法を知っている方がいましたら教えていただけると助かります…
【更新:解決】
無事、S3に画像がアップロードできるようになりました😆
記事の追記をご覧ください!
ActiveStorageについて
ActionTextは画像のアップロードにActiveStorageを使用していますので、ActiveStorageの設定を変更していきます。
画像の保存先を変更
config/environments/配下にあるファイルを変更します。
開発環境なら「development.rb」、本番環境なら「production.rb」を開きます。
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
となっている行を以下のように変更します。
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :amazon
保存先の設定を追加
上記で変更した「:amazon」という保存先の設定を追加します。config/storage.ymlを変更します。
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:
# service: S3
# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
# region: us-east-1
# bucket: your_own_bucket
となっている行のコメントアウトを外し、各値を設定します。
access_key_idとsecret_access_keyはCredentialsを使って設定します。
Credentialsの設定
ターミナルで以下のコマンドを実行します。
$ EDITOR=vi rails credentials:edit
すると、Credentialsの設定がviで編集できるようになります。
# aws:
# access_key_id: 123
# secret_access_key: 345
となっている行のコメントアウトを外し、access_key_idとsecret_access_keyを設定します。
CORSの設定を変更
Amazon S3のCORSの設定はGUIからは変更できないので、コマンドラインツールのawscliを使います。
awscliのインストールとセットアップは省略します。
適当なディレクトリにCORS.jsonを作成し、以下のように設定します。
{
"CORSRules": [
{
"AllowedOrigins": ["http://localhost:3000"],
"AllowedMethods": ["GET", "POST", "PUT"],
"MaxAgeSeconds": 3000,
"AllowedHeaders": ["*"]
}
]
}
続いて、以下のコマンドを実行します。
$ aws s3api put-bucket-cors --profile s3_config --bucket バケット名 --cors-configuration file://CORS.json
CORS.jsonの内容に不備があるとエラーが帰ってきます。正常にいけば何も帰ってきません。
Amazon S3のコンソール画面でCORSの設定画面を見ると、先ほど作成したCORSの設定が反映されていることがわかります。
それでもうまくいかない…
Umm...
実際にリッチテキストエディターで画像を投稿すると、画像だけ無視されて投稿されてしまいます。
画像だけで投稿しようとするとバリデーションエラーが発生します。
ログでは正常にS3にアップロードされているように見えるんですが…
Started POST "/rails/active_storage/direct_uploads" for ::1 at 2019-09-07 00:07:12 +0900
Processing by ActiveStorage::DirectUploadsController#create as JSON
Parameters: {"blob"=>{"filename"=>"759647.jpg", "content_type"=>"image/jpeg", "byte_size"=>1124951, "checksum"=>"aNJX53d715bfIlPCp+kxng=="}, "direct_upload"=>{"blob"=>{"filename"=>"759647.jpg", "content_type"=>"image/jpeg", "byte_size"=>1124951, "checksum"=>"aNJX53d715bfIlPCp+kxng=="}}}
(0.1ms) begin transaction
ActiveStorage::Blob Create (2.8ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?) [["key", "xtyzr6n5dqtkrtktaw4eyff6cqx7"], ["filename", "759647.jpg"], ["content_type", "image/jpeg"], ["byte_size", 1124951], ["checksum", "aNJX53d715bfIlPCp+kxng=="], ["created_at", "2019-09-07 00:07:13.831165"]]
(1.9ms) commit transaction
S3 Storage (1.9ms) Generated URL for file at key: xtyzr6n5dqtkrtktaw4eyff6cqx7 (https://バケット名.s3.ap-northeast-1.amazonaws.com/xtyzr6n5dqtkrtktaw4eyff6cqx7?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASDZCAGFGPBO5QBPX%2F20190906%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20190906T150713Z&X-Amz-Expires=300&X-Amz-SignedHeaders=content-md5%3Bcontent-type%3Bhost&X-Amz-Signature=759db267c76e158c753e0ccff9a9f488251f83a36d880395005a45b1a8a05613)
Completed 200 OK in 993ms (Views: 0.5ms | ActiveRecord: 6.1ms | Allocations: 140789)
宣伝
AUTOVICE - Heroku
※URLが間違っていました!
Railsの勉強としてシンプルなブログサービスを作りました。
勉強の記録なんかもこちらで公開していくつもりですので、ご興味のある方がいましたらご覧いただけると嬉しいです。
追記
初めに書いておくと、新たにどこかを設定し直したわけではありません。
画像のアップロード方法を少し変えただけです。
Action Textの場合、画像をアップロードするには2つの方法があります。
ひとつは以下の画像の画像選択アイコンをクリックし、ダイアログを呼び出して画像を選択する方法。
もうひとつは、ExplorerやFinderから画像をドラッグ&ドロップする方法。
私はこれまでずっと方法1の方法で試していました。
しかしふと、方法2の方法を試していないことに気が付き、試してみることにしました。
結果は言わずもがな、画像をS3にアップロードすることに成功しました!
そして気づいたんですが、リッチテキストエディターに画像を貼り付けた時点でS3へのアップロードが完了しているようです。
その後、方法1と方法2のやり方で同時に画像アップロードしたらどうなるかを試してみました。
私の予想では、方法1の画像は無視され、方法2の画像のみアップロードされると思っていたんですが、予想に反して両方ともアップロードされてしまいました😳
これ以降、方法1でも画像アップロードできるようになりました…
消化不良な結論で申し訳ありませんが、とにかく画像アップロードできるようになったので良しとさせてください😅
あ、そういえば、記事を削除したらS3の画像も一緒に削除される方法とかあるのかな…