ActiveStorageの必要性
長年愛用していたRailsのファイルアップロードgemであるpaperclipがDeprecationとなってしまったため、仕方なくActiveStorageを使ってみたところ、PublicなURL(S3への直接のURL)が取得できませんでした。
仕方なく別途S3用のクラウドサービスを追加して対応しました。
環境
- Rails 5.2.1
- ActiveStorage 5.2.1
問題点
ActiveStorageではデフォルトでクラウドサービスへのアップロードに対応しており
- AWS S3
- GCP Cloud Storage
- Azure Storage
へのファイルアップロードは設定ファイルを書くだけで対応できます。
ただし、ファイルアップロードの際にアクセス権限を指定することができずS3ではprivateでのファイルアップロードとなります。
下記がgem内のS3サービスのファイルです。
ファイルアップロード処理(put)で渡しているoptionにacl(アクセス権限)が含まれていません。
@upload_options
への設定の渡し方を調べればなんとかなるとは思っていましたが、次に調べたURLの取得でファイル自体を変更しないといけないことが判明しました。
def initialize(bucket:, upload: {}, **options)
@client = Aws::S3::Resource.new(**options)
@bucket = @client.bucket(bucket)
@upload_options = upload
end
def upload(key, io, checksum: nil)
instrument :upload, key: key, checksum: checksum do
begin
object_for(key).put(upload_options.merge(body: io, content_md5: checksum))
rescue Aws::S3::Errors::BadDigest
raise ActiveStorage::IntegrityError
end
end
end
ファイルのURLを取得するときに事前署名URLpresigned_url
となり、URLを使い回すことや長期間使用することが想定されていません。
def url(key, expires_in:, filename:, disposition:, content_type:)
instrument :url, key: key do |payload|
generated_url = object_for(key).presigned_url :get, expires_in: expires_in.to_i,
response_content_disposition: content_disposition_with(type: disposition, filename: filename),
response_content_type: content_type
payload[:url] = generated_url
generated_url
end
end
ちなみに、expires_in
は最大1週間指定できるようですが、今回はOGPのog:imageに指定するURLに使用したかったのでPublicなURLじゃないと駄目です。
新S3サービスのファイルを作成
以下に既存の3サービスファイルからの修正点を記載します。
def upload(key, io, checksum: nil)
instrument :upload, key: key, checksum: checksum do
begin
# aclでpublic-readを指定して必ず公開設定に変更.
object_for(key).put(upload_options.merge(body: io, content_md5: checksum, acl: 'public-read'))
rescue Aws::S3::Errors::BadDigest
raise ActiveStorage::IntegrityError
end
end
end
# ... 略
def url(key, expires_in:, filename:, disposition:, content_type:)
instrument :url, key: key do |payload|
# public_url で署名なしのPublic URLを取得.
generated_url = object_for(key).public_url
payload[:url] = generated_url
generated_url
end
end
注意点
- S3へアップロードするファイルすべてが
public-read
になります。private
にアップロードするファイルとの共存はできなくなります。 - ActiveStorage gemをアップデートする場合は、互換性がなくなる可能性があるため、ベースのS3ファイルとの差分をチェックすること
はやくActiveStorage自体でPublic URLの対応をしてくれないだろうか…