ActiveStorage doesn't support any kind of nesting inside S3 bucket (as of Rails v6.0). But without nesting, managing Multi Tenant application will be just plain hard. Specially is you use different database/schema per tenant.

There would be two way to fix this. 1. Move ActiveStorage tables to common database/schema. (and add a tenant relation to those tables) 2. MonkeyPatch to provider! 3. I don't know!

I don't like monkey patching library code but also managing code is easier for me than changing database! So I chose 2nd option.

So what I did is simple. Just override the path in S3 service class of ActiveStorage. File: lib/active_storage/service/better_s3_service.rb

require 'aws-sdk-s3'
require 'active_storage/service/s3_service'
require 'active_support/core_ext/numeric/bytes'

module ActiveStorage
  class Service::BetterS3Service < Service::S3Service
    private

    def object_for(key)
      bucket.object(File.join(root, key))
    end

    def root
      @root ||= "#{Tenant.current&.id || 'global'}"
    end
  end
end

and my config/storage.yml

amazon:
  # service: S3
  service: BetterS3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  bucket: agdum
  region: us-east-1

Note the new service name! It should be BetterS3 instead of S3.




What's on your mind?