環境: 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
: モデルへのファイルの添付を表すモデル