環境: Rails 5.2 / 6.0
RailsのActive Storageを使ってAWS S3にファイルを保存すると、自動的に whZ3Y8VP3XV8WGqjyK2dyZ5j のようなキー名になります。これを images/developmenet/whZ3Y8VP3XV8WGqjyK2dyZ5j のようにフォルダ分けする方法です。Rails Guildesには載っていませんが、Active Storageのソースコードを見てて気付きました。
次のモデルがあるとします。
class User < ApplicationRecord
has_one_attached :image
end
ふつうの使い方では、user.image.attach に ActionDispatch::Http::UploadedFile を渡します。
user.image.attach(file)
user.image.attach には ActionDispatch::Http::UploadedFile だけでなく、ActiveStorage::Blob オブジェクトも渡せます。ActiveStorage::Blob を直接使ってアップロードし、その後にUserモデルにくっ付ける、ということができます。
次の例では、ActiveStorage::Blob にキーを指定して new したあと、upload メソッドにIO オブジェクトを指定してアップロードし、それから attach メソッドに渡しています。key に指定した文字列がS3のキー名なります。
def save_image(user, file)
if Rails.configuration.active_storage.service == :amazon
key = "images/#{Rails.env}/#{SecureRandom.hex}"
blob = ActiveStorage::Blob.new(key: key,
filename: file.original_filename, content_type: file.content_type)
blob.upload file.to_io
user.image.attach(blob)
else
user.image.attach(file)
end
end
ActiveStorage::Blob のソースでは、キーは次のように作られています。
class ActiveStorage::Blob < ActiveRecord::Base
# 略
has_secure_token :key
# 略
def key
# We can't wait until the record is first saved to have a key for it
self[:key] ||= self.class.generate_unique_secure_token
end
generate_unique_secure_token メソッドは ActiveRecord::SecureToken のソース中にあります。
def generate_unique_secure_token
SecureRandom.base58(24)
end
上記のサンプルは次のようにも書けます。ActiveStorage::Blob にキーを作らせておいてから、プレフィックスを付ける方法です。
blob = ActiveStorage::Blob.new(filename: file.original_filename,
content_type: file.content_type)
blob.key = "images/#{Rails.env}/#{blob.key}"
blob.upload file.to_io
Active Storage関連のテーブル
以下、ご参考までにメモ。
Active Storage関連のテーブルには、active_storage_blobs と active_storage_attachments があり、それぞれモデルクラス ActiveStorage::Blob と ActiveStorage::Attachment が対応しています。どちらも ActiveRecord::Base のサブクラスなので、ふつうのモデルのように使えます。
-
ActiveStorage::Blob: アップロードしたファイルを表すモデル -
ActiveStorage::Attachment: モデルへのファイルの添付を表すモデル
