Carrierwave + S3でのS3 object keyの決まり方
carrierwave
store
https://github.com/carrierwaveuploader/carrierwave/blob/32abf5b2caf7baa8fca74324009bc1fe1acbed14/lib/carrierwave/storage/fog.rb#L339-L352
storeメソッドででFog gem経由でクラウドストレージに置きに行く
code:for.rb
##
# Write file to service
#
# === Returns
#
# Boolean true on success or raises error
def store(new_file)
if new_file.is_a?(self.class)
new_file.copy_to(path)
else
fog_file = new_file.to_file
@content_type ||= new_file.content_type
@file = directory.files.create({
:body => fog_file ? fog_file : new_file.read,
:content_type => @content_type,
:key => path,
:public => @uploader.fog_public
}.merge(@uploader.fog_attributes))
fog_file.close if fog_file && !fog_file.closed?
end
true
end
pathというのがs3 objectのkeyになる
path
https://github.com/carrierwaveuploader/carrierwave/blob/32abf5b2caf7baa8fca74324009bc1fe1acbed14/lib/carrierwave/sanitized_file.rb#L111
code:sanitized_file.rb
##
# Returns the full path to the file. If the file has no path, it will return nil.
#
# === Returns
#
# String, nil the path where the file is located.
#
def path
return if @file.blank?
if is_path?
File.expand_path(@file)
elsif @file.respond_to?(:path) && !@file.path.blank?
File.expand_path(@file.path)
end
end
FileはSanitizedFileのインスタンス
retrieve https://github.com/carrierwaveuploader/carrierwave/blob/32abf5b2caf7baa8fca74324009bc1fe1acbed14/lib/carrierwave/storage/file.rb#L51-L53
code:file.rb
def retrieve!(identifier)
path = ::File.expand_path(uploader.store_path(identifier), uploader.root)
CarrierWave::SanitizedFile.new(path)
end
つまりpath == s3 object key == ::File.expand_path(uploader.store_path(identifier), uploader.root) できまる
uploader.store_pathのロジックはこう
https://github.com/carrierwaveuploader/carrierwave/blob/32abf5b2caf7baa8fca74324009bc1fe1acbed14/lib/carrierwave/uploader/store.rb#L37-L51
code:store.rb
##
# Calculates the path where the file should be stored. If +for_file+ is given, it will be
# used as the filename, otherwise +CarrierWave::Uploader#filename+ is assumed.
#
# === Parameters
#
# for_file (String) name of the file <optional>
#
# === Returns
#
# String the store path
#
def store_path(for_file=filename)
File.join(store_dir, full_filename(for_file).compact)
end
store_dir + full_filename(これはほぼ \#filename が使われる) になる
https://github.com/carrierwaveuploader/carrierwave/blob/32abf5b2caf7baa8fca74324009bc1fe1acbed14/lib/carrierwave/sanitized_file.rb#L57
code:sanitized_file.rb
def filename
sanitize(original_filename) if original_filename
end
filenameとしては基本アップロードしたファイル名が使われる
ということで基本 store_dir + アップロードしたファイル名 がs3 object keyになる。
model上で mount_uploader して使うとき、Uploader classの実装はだいたいtemplateからこうなる
https://github.com/carrierwaveuploader/carrierwave/blob/eca7b98aa92dcbf0326c1a650822f91fa8248b22/lib/generators/templates/uploader.rb.erb#L11-L14
code:uploader.rb.erb
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
store_dirを上書きして、model名や idを含めている。
なので、 /uploads/User/uploader/2/file.jpg みたいなs3 object keyになる。
---
雑感
S3に上げるだけだと store_dir いらねえよなぁと思う
def store_dir = Rails.env.local? ? "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" : '/'
def filename = SecureRandom.uuid とかでいけないかな...
試してない いけなそう...
dbに永続化した上でファイル保存することになり(つまりs3 object keyをレコード永続化前に得ることができない)場合によっては不便
近年では ActiveStorage を使えば良いので新規に使う利点はない
carrirewaveはContent-TYpeを保存してくれたりする機能がデフォで存在しないなども使い勝手がよくない