😸
ActiveStorage あれこれ試す
Active Storage を試す
- 上記を基に実際に触ってみる
- 今回は AWS S3 を Storage として利用する
- Ruby 3.0.3
- Rails 6.1.4
前提
- 唯一存在する Controller/Model 名は pages/page これを基に rails c などをしている
Rails.application.routes.draw do
root 'pages#index'
resources :pages
end
Command
Gem
gem 'aws-sdk-s3', '1.48', require: false
初期準備
- master.key を基に暗号化される credentials.yml.enc
- credentials を実行したタイミングで master.key が config 配下に生成されるようだ
EDITOR=vi rails credentials:edit
rails active_storage:install
rails db:migrate
AWS Key設定 ( EDITOR=vi rails credentials:edit の内容 )
aws:
access_key_id: 使いたいS3のアクセス権限がある access_key
secret_access_key: 使いたいS3のアクセス権限がある secret_key
Config ( storage.yml )
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: 使いたいS3が存在する Region #実際には .env とかに
bucket: 使いたいS3の bucket name #実際には .env とかに
Config ( environments / development.rb )
config.active_storage.service = :amazon
# config.active_storage.service = :local
Attache を試す
View ( pages / index.html.erb )
<div class="col-md-6 col-md-offset-3">
<%= form_with model: @page, method: :post, url: pages_path, local: true do |f| %>
<%= f.label :image %>
<%= f.file_field :image, class: 'form-control' %>
<%= f.submit "Upload", class: "btn btn-primary" %>
<% end %>
</div>
<div class="col-md-6 col-md-offset-3">
<% @page.each do | page | %>
<img src ="https://shibano-test.s3.ap-northeast-1.amazonaws.com/<%= page.image.key if page.image.attached? %>">
<% end %>
</div>
Model ( page.rb )
class Page < ApplicationRecord
has_one_attached :image
end
Controller ( pages_controller.rb )
def create
Page.create!(page_params)
redirect_to root_path
end
private
def page_params
params.require(:page).permit( :id, :image)
end
確認
なんの変哲もないただの初期画面
アップロードしてみた
- が、S3直アクセスはS3側で public read 設定がないと Access Denied になる
- 今回はお試しなので、手動で public read を付与した
- サービスで利用する場合には Cloudfront + s3 や Web host として公開など。
Purge を試す(rasil console)
-
view から指定削除しようかとも思ったけども、、、そこまで試すのが億劫だったので rails c で軽く動作を確認する程度
-
ファイル実体は消える
-
acched? も false となる
[1] pry(main)> page = Page.last
Page Load (2.1ms) SELECT `pages`.* FROM `pages` ORDER BY `pages`.`id` DESC LIMIT 1
=> #<Page:0x00007f7f61b64c38 id: 1, created_at: Mon, 07 Feb 2022 12:38:22.339445000 UTC +00:00, updated_at: Mon, 07 Feb 2022 12:38:22.393025000 UTC +00:00, comment: nil>
[2] pry(main)> page.image.purge
ActiveStorage::Attachment Load (3.6ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'Page' AND `active_storage_attachments`.`name` = 'image' LIMIT 1
TRANSACTION (3.8ms) BEGIN
ActiveStorage::Attachment Destroy (5.0ms) DELETE FROM `active_storage_attachments` WHERE `active_storage_attachments`.`id` = 1
Page Update (3.9ms) UPDATE `pages` SET `pages`.`updated_at` = '2022-02-07 12:40:54.042033' WHERE `pages`.`id` = 1
TRANSACTION (5.6ms) COMMIT
ActiveStorage::Blob Load (1.5ms) SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 1 LIMIT 1
TRANSACTION (1.6ms) BEGIN
ActiveStorage::Attachment Exists? (1.8ms) SELECT 1 AS one FROM `active_storage_attachments` WHERE `active_storage_attachments`.`blob_id` = 1 LIMIT 1
ActiveStorage::VariantRecord Load (1.9ms) SELECT `active_storage_variant_records`.* FROM `active_storage_variant_records` WHERE `active_storage_variant_records`.`blob_id` = 1
ActiveStorage::Attachment Load (2.5ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'ActiveStorage::Blob' AND `active_storage_attachments`.`name` = 'preview_image' LIMIT 1
ActiveStorage::Blob Destroy (3.2ms) DELETE FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 1
TRANSACTION (3.4ms) COMMIT
S3 Storage (167.8ms) Deleted file from key: yyn1zjlr1id7nigrlv3yyehy995p
S3 Storage (66.0ms) Deleted files by key prefix: variants/yyn1zjlr1id7nigrlv3yyehy995p/
=> nil
[3] pry(main)> page.image.attached?
ActiveStorage::Attachment Load (5.0ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'Page' AND `active_storage_attachments`.`name` = 'image' LIMIT 1
=> false
[4] pry(main)>
mysql> select * from active_storage_blobs;
Empty set (0.00 sec)
mysql>
- ファイル実体もちゃんと消えている
Tips ( 使いそうな物 )
s3 にあげた時のファイル名が知りたい
- S3 の実体が乱数である事にお気づきであろうか。実際にどこになんの情報が確認されているのかを追ってみよう。
- ファイル実体情報は下記
active_storage_blobs
に格納されている。 - filename は upload した時に渡された ファイル名
- key が s3 に配置された時の ファイル名である
- ※
アップロードしてみた
の画像キャプチャ参照
- ※
mysql> select * from active_storage_blobs;
+----+------------------------------+------------+--------------+-------------------------------------+--------------+-----------+--------------------------+---------------------+
| id | key | filename | content_type | metadata | service_name | byte_size | checksum | created_at |
+----+------------------------------+------------+--------------+-------------------------------------+--------------+-----------+--------------------------+---------------------+
| 3 | ldkba65mdfczd1u5ccoycz8hmrtb | amazon.png | image/png | {"identified":true,"analyzed":true} | amazon | 3846 | l+FlMT1sjISVAR5FaaJX2Q== | 2022-02-07 13:14:56 |
+----+------------------------------+------------+--------------+-------------------------------------+--------------+-----------+--------------------------+---------------------+
1 row in set (0.00 sec)
mysql>
- model との紐付けはこちら(多分...
- record_id ...? page_id じゃないのは色々な Model が絡む可能性があるので?Model名は record_type に入る...?のかな。しらんけど
mysql> select * from active_storage_attachments;
+----+-------+-------------+-----------+---------+---------------------+
| id | name | record_type | record_id | blob_id | created_at |
+----+-------+-------------+-----------+---------+---------------------+
| 3 | image | Page | 3 | 3 | 2022-02-07 13:14:56 |
+----+-------+-------------+-----------+---------+---------------------+
1 row in set (0.00 sec)
mysql> select * from pages where id = '3';
+----+----------------------------+----------------------------+---------+
| id | created_at | updated_at | comment |
+----+----------------------------+----------------------------+---------+
| 3 | 2022-02-07 13:14:56.486984 | 2022-02-07 13:14:56.528141 | NULL |
+----+----------------------------+----------------------------+---------+
1 row in set (0.00 sec)
- ファイル名を元に何かしたい場合には key を利用すれば良い
[2] pry(main)> page.image.key
ActiveStorage::Attachment Load (4.7ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 3 AND `active_storage_attachments`.`record_type` = 'Page' AND `active_storage_attachments`.`name` = 'image' LIMIT 1
ActiveStorage::Blob Load (1.5ms) SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 3 LIMIT 1
=> "ldkba65mdfczd1u5ccoycz8hmrtb"
[3] pry(main)>
商用で利用する時
配信まわり
- 画像配信周りの S3 を切り出したい ( Imagekit とか画像圧縮専用サービスをかます時楽 )
- もしくは静的ファイル専用の S3 を切り出す ( めっちゃキャッシュするよバケットで切り出す )
- 1 domain 構成の場合には、PATH を指定しやすい形にしておくほうが良い。
- .env と view の記載方法をあらかじめ分けて書いておきましょうね。
運用まわり
- DB レコード = bucket file の存在チェックが必要...?
Discussion