Jun 02, 2024

Global prerocessor for ActiveStorage

Today I would like to show you how to implement global preprocessing of uploaded files in Rails. Unfortunately, ActiveStorage does not make it possible to do this simply and explicitly, or I just did not find any information about it.

However, we can implement global preprocessing of files uploaded to ActiveStorage. To do this, we can use a frankly bad technique, we can redefine three methods in ActiveStorage::Blob. Here they are build_after_upload, build_after_unfolding and upload. Here I mean Rails 6.1.

# lib/active_storage/blob_preprocessor.rb
module ActiveStorage
  module BlobPreprocessor
    def build_after_upload(io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil) #:nodoc:
      preprocess!(io)
      super(io: io, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, identify: identify, record: record)
    end

    def build_after_unfurling(key: nil, io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil) #:nodoc:
      preprocess!(io)
      super(key: key, io: io, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, identify: identify, record: record)
    end

    def upload(io, identify: true)
      preprocess!(io)
      super(io, identify: identify)
    end

    def preprocess!(io)
      # Here we can do everything with io Tempfile, but we should not change its path.
      # Thats why this method doesn't return new Tempfile.
    end
  end
end

And finally, we need to patch the main class.

# config/application.rb
#...
    config.to_prepare do
      ActiveStorage::Blob.singleton_class.include ActiveStorage::BlobPreprocessor
    end
#...