ActiveStorageSaas
ActiveStorageSaas 是一个 Rails gem,为 ActiveStorage 提供多租户存储服务支持。它允许每个租户配置自己的存储服务,并支持动态加载不同的存储服务。
功能特性
- 🏢 多租户支持:每个租户可以配置独立的存储服务
- 🔄 动态服务加载:根据 blob 的 service_name 动态解析并加载对应的存储服务
- 🔌 灵活配置:支持通过数据库配置存储服务选项
- 📦 完全兼容:与 Rails ActiveStorage API 完全兼容,无需修改现有代码
- 🚀 直接上传支持:支持 ActiveStorage 的直接上传功能
安装
在 Gemfile 中添加:
ruby
gem 'activestorage_saas', '~> 7.2.3'
然后运行:
bash
bundle install
运行安装生成器:
bash
rails generate active_storage_saas:install
这将创建必要的迁移文件。运行迁移:
bash
rails db:migrate
配置
1. 数据库迁移
安装生成器会创建一个 storage_service_configurations 表,用于存储每个租户的存储服务配置。
2. 存储配置 (config/storage.yml)
在 config/storage.yml 中配置一个 saas 服务作为包装器:
```yaml saas: service: Saas default_service: local # 默认使用的存储服务
local: service: Disk root: <%= Rails.root.join(“storage”) %>
amazon: service: S3 access_key_id: <%= ENV[‘AWS_ACCESS_KEY_ID’] %> secret_access_key: <%= ENV[‘AWS_SECRET_ACCESS_KEY’] %> region: us-east-1 bucket: my-bucket ```
3. 应用配置 (config/application.rb 或 config/environments/*.rb)
```ruby Rails.application.configure do # 可选:自定义服务解析器 # config.active_storage_saas.service_resolver = ->(blob) { # StorageServiceConfiguration.from_service_name(blob.service_name)&.to_service # }
# 可选:自定义服务名称转换器(用于直接上传) # config.active_storage_saas.service_name_converter = ->(controller) { # controller.send(:current_tenant).storage_service&.to_service_name # }
# 可选:自定义服务名称验证器 # config.active_storage_saas.service_name_validator = ->(service_name) { # StorageServiceConfiguration.valid_service_name?(service_name) # }
# 可选:直接上传时额外的 blob 参数 # config.active_storage_saas.direct_upload_extra_blob_args = ->(controller) { # { tenant: controller.send(:current_tenant) } # } end ```
使用方法
创建存储服务配置
```ruby # 为租户创建存储服务配置 config = StorageServiceConfiguration.create!( service_name: ‘amazon’, # 基础服务名称(在 storage.yml 中定义) service_options: { bucket: ‘tenant-specific-bucket’, region: ‘us-west-2’ } )
获取服务名称(格式:StorageServiceConfiguration:123)
service_name = config.to_service_name ```
使用存储服务
```ruby # 创建 blob 时指定服务名称 blob = ActiveStorage::Blob.create!( filename: ‘example.jpg’, byte_size: 1024, checksum: ‘abc123’, content_type: ‘image/jpeg’, service_name: config.to_service_name # 使用动态服务名称 )
blob.service 会自动解析为对应的存储服务实例
blob.service # => 返回配置的 S3 服务实例 ```
在模型中关联文件
```ruby class User < ApplicationRecord has_one_attached :avatar end
上传文件时指定服务
user.avatar.attach( io: file, filename: ‘avatar.jpg’, service_name: current_tenant.storage_config.to_service_name ) ```
工作原理
SaasService
SaasService 是一个包装器服务,它:
- 接收一个
blob对象 - 根据
blob.service_name动态解析对应的存储服务 - 将所有方法调用委托给实际的存储服务
服务解析流程
- 当访问
blob.service时,会调用ActiveStorageSaas.service_resolver - 解析器根据
service_name查找对应的StorageServiceConfiguration - 配置对象通过
to_service方法创建实际的存储服务实例 - 如果解析失败,回退到默认服务
服务名称格式
动态服务的名称格式为:ClassName:ID,例如:
- StorageServiceConfiguration:1
- StorageServiceConfiguration:42
这种格式允许从服务名称中提取配置记录的 ID。
高级用法
自定义服务解析器
ruby
config.active_storage_saas.service_resolver = ->(blob) {
tenant = blob.record&.tenant
tenant&.storage_config&.to_service
}
多租户集成示例
```ruby class Tenant < ApplicationRecord has_one :storage_service_configuration, class_name: ‘StorageServiceConfiguration’ end
class ApplicationController < ActionController::Base def current_tenant @current_tenant ||= Tenant.find(session[:tenant_id]) end end
在配置中
config.active_storage_saas.service_name_converter = ->(controller) { controller.current_tenant.storage_service_configuration.to_service_name } ```
兼容性
- Rails 版本:7.2.3
- Ruby 版本:>= 2.6.0
- ActiveStorage 版本:7.2.3
开发
运行测试:
bash
bundle exec rspec
运行控制台:
bash
bin/console
贡献
欢迎提交 Issue 和 Pull Request!
许可证
MIT License