carrierwaveとfog-googleでGCSに静的ファイルをアップロードしたり、ローカルと本番でどう切り替えていくかについて、試してみたことを書き連ねていきます。
※特に目新しいことはしておらず、既に出回っている記事以上のことは書いていないと思います
carrierwaveのREADME の手順に沿って、環境構築していきます。
uploaderクラスをこれで生成します。
bin/rails g uploader Avatar
Userテーブルにnameとavatarを保存するカラムを用意します。
bin/rails g model User name:string avatar:string
bin/rails db:migrate
次に公式に従って以下を定義します。
class User < ApplicationRecord
mount_uploader :avatar, AvatarUploader
end
ここまで公式の手順に従ってやってきました。
これでuserテーブルにavatarのパスを保存できる準備が整います。
rails consoleで試してみます。
bin/rails c
u = User.new
u.name = 'tanaka'
file = File.open('/Users/tanaka/Desktop/hoge.png')
u.avatar = file
u.save!
u.avatar
=>
#<AvatarUploader:0x00000001105974d0
@cache_id=nil,
@cache_storage=#<CarrierWave::Storage::File:0x00000001106db170 @cache_called=nil, @uploader=#<AvatarUploader:0x00000001105974d0 ...>>,
@deduplication_index=nil,
@file=
#<CarrierWave::SanitizedFile:0x00000001102dadc8
@content=nil,
@content_type=nil,
@declared_content_type=nil,
@file="/Users/tanaka/work/project/examples/carrierwave-cdn-gcs-signedurl/public/uploads/user/avatar/1/hoge.png",
@original_filename=nil>,
@filename="hoge.png",
@identifier="hoge.png",
@model=#<User:0x000000010f1af698 id: 1, name: "tanaka", avatar: "hoge.png", created_at: Sun, 26 Nov 2023 03:16:54.005319000 UTC +00:00, updated_at: Sun, 26 Nov 2023 03:16:54.005319000 UTC +00:00>,
@mounted_as=:avatar,
@original_filename=nil,
@staged=false,
@storage=#<CarrierWave::Storage::File:0x0000000110678688 @cache_called=nil, @uploader=#<AvatarUploader:0x00000001105974d0 ...>>,
@versions={}>
u.avatar.url
=> "/uploads/user/avatar/1/hoge.png"
u.avatar.curent_path
=> "/Users/tanaka/work/project/examples/carrierwave-cdn-gcs-signedurl/public/uploads/user/avatar/1/hoge.png"
こんな感じでavatar.{url,current_path}
でpathを引っ張ってくることができます。
ローカルだとプロジェクトのpublic/uploads/user/**
にファイルが保存されています。
公式を参考にdevelopmentとproductionでcarrierwaveのstorageを:file
か:fog
に切り替えるようにする。
CarrierWave.configure do |config|
if %w(staging production).include?(Rails.env)
config.fog_provider = 'fog/google'
config.fog_credentials = {
provider: 'Google',
google_project: Rails.application.credentials.google_project,
google_json_key_string: Rails.application.credentials.google_json_key_string,
# google_json_key_location: '',
}
config.fog_directory = Rails.application.credentials.gcs_bucket
config.fog_public = nil
config.storage = :fog
config.cache_storage = :fog
else
config.storage = :file
end
end
こんな感じでinitializers/carrierwave.rb
に定義します。
あとはproduction用のdbは適当にローカルで用意してやれば、consoleでファイルアップロードが試せるはずです。
bin/rails c
u = User.new
u.name = 'hoge'
file = File.open('/Users/hoge/Desktop/hengao_mabuta_uragaesu.png')
u.avatar = file
u.save!
u.avatar
=>
#<AvatarUploader:0x0000000110f6d5e0
@cache_id=nil,
@deduplication_index=nil,
@file=
#<CarrierWave::Storage::Fog::File:0x0000000112a4bba0
@base=#<CarrierWave::Storage::Fog:0x0000000110f6c4d8 @uploader=#<AvatarUploader:0x0000000110f6d5e0 ...>>,
@content_type=nil,
@path="uploads/user/avatar/1/hengao_mabuta_uragaesu.png",
@uploader=#<AvatarUploader:0x0000000110f6d5e0 ...>>,
@filename=nil,
@identifier="hengao_mabuta_uragaesu.png",
@model=#<User:0x0000000112559390 id: 1, name: "hoge", avatar: "hengao_mabuta_uragaesu.png", created_at: Sun, 26 Nov 2023 07:57:37.885654000 UTC +00:00, updated_at: Sun, 26 Nov 2023 07:57:37.885654000 UTC +00:00>,
@mounted_as=:avatar,
@staged=false,
@storage=#<CarrierWave::Storage::Fog:0x0000000110f6c4d8 @uploader=#<AvatarUploader:0x0000000110f6d5e0 ...>>,
@versions={}>
u.avatar.url
=> "https://storage.googleapis.com/{bucket name}/uploads/user/avatar/1/hengao_mabuta_uragaesu.png?GoogleAccessId={service account email}&Signature=Pgi0Erp517jf%2B37ns9nWcdgNppU1H2ieZJ6Ls59GvzRlrVqMuYSToTI3el6g%0AUv%2FuSzm%2BpxOAL34kTgX7vlk1jAlRiC4SHL80ShLXi3ZomaEbnGOdspFquxXU%0AsL03%2FdL8h3eQOOb6hvf3GH3eY74QMbhQoJjtS0gLX0yQ2l9zADqgKBaNMg9F%0A9RSwZAPcgObO%2BuuYktmvJlOpA4qt7k2K2spCT24dgbhz99TP1gWO8NBocHV%2B%0Ax9DOXGHoe6w0MZUaBssLGaoYu572qf%2FSBYmUPRjc5a2TNSf5%2BPyQqL7FoCDY%0ARWm4c5FEB21M9Lo6sKRLvYXtpn1Q6oXbjhIsdUScvA%3D%3D&Expires=1700987087"
u.avatar.path
=> "uploads/user/avatar/1/hengao_mabuta_uragaesu.png"
このようにRails.env
を切り替えることでローカルストレージかGCSかを切り替えることが容易にできるみたいです。
urlやpathも返すことができるので、このstorage.googleapis.comのurlを使ってReactなどのフロント側は、fetchすれば画像表示も容易に実装できると思います。
補足ですが、今回の検証に使っているGCSは非公開に設定しているため、署名がない限り参照できないようになっています。
今回使用したコードはこちらです。
https://github.com/ksaito422/carrierwave-cdn-gcs-signedurl