Open-Source Wikis

/

Ruby on Rails

/

Packages

/

Active Storage

rails/rails

Active Storage

Active contributors: rafaelfranca, georgeclaghorn, byroot

Purpose

Active Storage attaches files to Active Record models and stores them on local disk or a cloud service (S3, GCS, Azure via a separate gem). It provides direct uploads, image transformation, audio/video transcoding, metadata extraction, and previews.

Source: activestorage/lib/active_storage/ plus activestorage/app/. ~3,900 lines of lib/ Ruby and a JavaScript direct-upload client.

Directory layout

activestorage/
├── app/
│   ├── controllers/active_storage/      # Blob, Direct upload, Disk service controllers
│   ├── jobs/active_storage/             # AnalyzeJob, MirrorJob, PurgeJob, TransformJob
│   ├── models/active_storage/           # Blob, Attachment, Variant, VariantRecord, Preview
│   ├── javascript/                      # Direct upload JS client
│   └── assets/                          # Stylesheets
├── config/
│   └── routes.rb                        # /rails/active_storage/* routes
├── db/migrate/                          # active_storage_blobs, attachments, variant_records
├── lib/
│   └── active_storage/
│       ├── analyzer/                    # Image, video, audio metadata extraction
│       ├── analyzer.rb
│       ├── attached/                    # has_one_attached, has_many_attached
│       ├── attached.rb
│       ├── engine.rb
│       ├── errors.rb
│       ├── fixture_set.rb
│       ├── log_subscriber.rb
│       ├── previewer/                   # PDF, Video → image preview
│       ├── previewer.rb
│       ├── reflection.rb
│       ├── service/                     # Disk, S3, GCS, Mirror
│       ├── service.rb
│       ├── structured_event_subscriber.rb
│       └── transformers/                # ImageMagick, libvips, video
└── activestorage.gemspec

Key abstractions

Constant File Purpose
ActiveStorage::Blob activestorage/app/models/active_storage/blob.rb One stored file plus metadata
ActiveStorage::Attachment activestorage/app/models/active_storage/attachment.rb Join row tying a blob to a parent record
ActiveStorage::Service activestorage/lib/active_storage/service.rb Base class for storage backends
ActiveStorage::Service::DiskService activestorage/lib/active_storage/service/disk_service.rb Local filesystem backend
ActiveStorage::Service::S3Service activestorage/lib/active_storage/service/s3_service.rb AWS S3 backend
ActiveStorage::Service::GCSService activestorage/lib/active_storage/service/gcs_service.rb Google Cloud Storage backend
ActiveStorage::Service::MirrorService activestorage/lib/active_storage/service/mirror_service.rb Wrap multiple services for replication
ActiveStorage::Variant activestorage/app/models/active_storage/variant.rb Image transformation result
ActiveStorage::Preview activestorage/app/models/active_storage/preview.rb Preview image (PDF, video)
ActiveStorage::Analyzer activestorage/lib/active_storage/analyzer/ Extract dimensions, duration, etc.
ActiveStorage::Previewer activestorage/lib/active_storage/previewer/ Generate preview image from non-image
ActiveStorage::Transformers::* activestorage/lib/active_storage/transformers/ ImageMagick / libvips / ffmpeg backends

How attachment works

class User < ApplicationRecord
  has_one_attached :avatar
  has_many_attached :photos
end

Implementation lives in activestorage/lib/active_storage/attached/:

  • model.rb — the has_one_attached and has_many_attached macros.
  • one.rb / many.rb — proxies returned by user.avatar / user.photos.
  • changes/ — pending attach / detach operations bundled with the parent record's lifecycle.

When you call user.avatar.attach(file), an ActiveStorage::Attachment row is created pointing to a new (or existing) ActiveStorage::Blob. The blob has a service_name, key, byte_size, checksum, content_type, and metadata.

Storage services

activestorage/lib/active_storage/service/:

  • DiskService — writes under Rails.root.join("storage"). Used in dev/test by default.
  • S3Service — uses the aws-sdk-s3 gem (declared in the host app's Gemfile, not Active Storage's gemspec).
  • GCSService — uses google-cloud-storage.
  • MirrorService — composite that mirrors writes to multiple services and reads from a primary. Useful during a storage migration.
  • Azure was extracted into the separate azure-storage-blob gem in 7.x.

Each service implements:

  • upload(key, io, ...) / download(key, &block) / delete(key) / exist?(key)
  • url_for_direct_upload(key, ...) — pre-signed upload URL
  • url(key, ...) — pre-signed download URL
  • headers_for_direct_upload(key, ...) — required headers for the direct upload

Direct uploads

The direct_uploads_controller (activestorage/app/controllers/active_storage/direct_uploads_controller.rb) issues a pre-signed URL plus headers; the JS client uploads directly to S3/GCS/disk without bouncing through the Rails server. Implementation in activestorage/app/javascript/active_storage/direct_upload.js.

Variants and previews

ActiveStorage::Variant represents a derived image:

user.avatar.variant(resize_to_limit: [100, 100])

The transformation is described by an ActiveStorage::Transformer (activestorage/lib/active_storage/transformers/image_processing_transformer.rb). The image_processing gem is the supported backend, which itself wraps mini_magick (ImageMagick) or ruby-vips (libvips).

Previews handle non-image files: PDFs (Poppler), videos (ffmpeg). Previewers live in activestorage/lib/active_storage/previewer/.

Analyzers

activestorage/lib/active_storage/analyzer/:

  • null_analyzer.rb
  • image_analyzer.rb (with vips.rb and image_magick.rb flavors)
  • audio_analyzer.rb
  • video_analyzer.rb

When a blob is uploaded, an AnalyzeJob runs through analyzers in order; the first matching one writes its findings into blob.metadata.

Background jobs

activestorage/app/jobs/active_storage/:

  • analyze_job.rb — runs analyzers after upload.
  • mirror_job.rb — copies a blob to mirrored services.
  • purge_job.rb — cleans up after a record is destroyed.
  • transform_job.rb — pre-generates variant images.

Engine

activestorage/lib/active_storage/engine.rb is a Rails::Engine that:

  • Mounts /rails/active_storage/ routes (representations, blobs, direct uploads).
  • Runs the migration to create active_storage_blobs, active_storage_attachments, and active_storage_variant_records.
  • Wires has_one_attached / has_many_attached into Active Record via a lazy load hook.

Integration points

  • Active Record — host records, attachment join model.
  • Active Job — analyses, transformations, purges.
  • Action Text — embedded blobs are Active Storage attachments.
  • Action Mailbox — raw inbound emails are stored as blobs.
  • Action Pack — controllers under /rails/active_storage/.

Entry points for modification

  • Adding a service: subclass ActiveStorage::Service and implement the upload/download/url methods. Tests under activestorage/test/service/<name>_service_test.rb.
  • Adding an analyzer: subclass ActiveStorage::Analyzer, register via config.active_storage.analyzers.
  • Adding a previewer: subclass ActiveStorage::Previewer, register via config.active_storage.previewers.
  • Modifying the direct upload protocol: changes to the controller, the JS client, and the service-specific headers_for_direct_upload must stay in sync.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Active Storage – Ruby on Rails wiki | Factory