Rails >= 6.1 开始,ActiveStorage
开始支持多个 storage service,可能不算新闻(这里有篇 blog 介绍),但是最近升上 6.1 来才用到它,分享一下。
在存储的时候,可能会有不同的存储服务,比如我们的要把图片存在 Cloudinary,其他文件存在 Amazon S3。在 6.1 之前,我们是打了一个 monkey patch;在 6.1 之后,就可以直接配置啦。
# config/initializers/activestorage.rb
Rails.application.config.to_prepare do
ActiveStorage::Blob.class_eval do
alias_method :original_service, :service
def service
return original_service if self.image?
@service ||= load_active_storage_service(:amazon)
end
private
def load_active_storage_service(service)
ActiveStorage::Service.configure service, Rails.configuration.active_storage.service_configurations
rescue => e
raise e, "Cannot load service #{service}`:\n#{e.message}", e.backtrace
end
end
# ...
end
Monkey patch 就可以完全去掉了,因为 service 变得可以配置了;config/storage.yml 可以稍微修改下:
amazon:
service: S3
access_key_id: <%= ENV['s3_access_key_id'] %>
secret_access_key: <%= ENV['s3_secret_access_key'] %>
bucket: <%= ENV['s3_bucket'] %>
region: <%= ENV['s3_region'] %>
cloudinary:
service: Cloudinary
fetch_format: auto
quality: auto
secure: true
folder: <%= 'dev' if Rails.env.development? %>
然后在模型里,就可以这样:
class Posting < ApplicationRecord
has_many_attached :images, service: :cloudinary
has_one_attached :thumbnail, service: :cloudinary
end
class Project < ApplicationRecord
has_one_attached :doc, service: :amazon
end