Rails 與 fog-aws 與 carrierwave 打一套上傳組合拳
記錄使用 carrierwave 搭配 fog-aws 將圖片上傳到 s3 將靜態資源外部化
上傳檔案到外部空間是一個很基本的需求,好處有很多例如,轉移主機時只要把程式碼打包帶走,或是礙於主機限制容量大小,又或是像 Heroku 不提供存放空間等。
那為何我們不使用 fog
反而使用 fog-aws
因為 fog
裡面有太多的 SDK 依賴了,如果整個系統只有一個上傳空間,只需要使用對應的 gem 就好了,像是 fog
的 readme 自己也有說:
If there's a metagem available for your cloud provider, e.g. fog-aws, you should be using it instead of requiring the full fog collection to avoid unnecessary dependencies.
AWS 權限與建立
-
建立一個 s3 bucket
記得 Object Ownership 要選 ACLs enabled
-
把 bucket 設為公開
-
建立一個 IAM 專門用來上傳
這個是我的 policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::YOUR_BUCKET",
"arn:aws:s3:::YOUR_BUCKET/*"
]
}
]
}
- 取得 Access ID 跟 key
安裝 gem
gem 'fog-aws'
gem 'carrierwave'
版本可以自己決定是否要指定,沒意外設定方式應該是不會變動才對
接著建立一個 config/initializers/carrierwave.rb
# frozen_string_literal: true
CarrierWave.configure do |config|
if Rails.env.production? || Rails.env.staging?
config.fog_provider = 'fog/aws'
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID') || 'ABCDE',
aws_secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY') || 'ABCDE',
region: 'ap-northeast-1'
}
config.fog_directory = ENV.fetch('AWS_BUCKET') || 123
}
else
config.storage = :file
end
end
我這邊是讓開發本地把上傳圖片丟進本地 file 省的開發浪費空間資源。
接著就可以去設定我們的 uploader 例如:
class ImageUploader < CarrierWave::Uploader::Base
# ...
# Choose what kind of storage to use for this uploader:
if Rails.env.production? || Rails.env.staging?
storage :fog
else
storage :file
end
# ...
end
如果你的設定都正確的話,ImageUploader
就會把資源丟去 s3 上去了。