Rails 6.1 tracks Active Storage variant in the database

Rails 6.1 introduced database tracking for Active Storage variants, significantly reducing latency by storing variant information in the database instead of generating them on-the-fly.

Before Rails 6.1

Previously, Active Storage variants were generated on-demand and stored in the storage service. This meant:

  • Variants were created when first requested
  • No database record of variants existed
  • Each request potentially triggered variant generation
  • Higher latency for variant access

Rails 6.1 Solution

Rails 6.1 tracks variants in the database through the active_storage_variant_records table, providing:

  • Faster variant access
  • Better tracking of generated variants
  • Reduced storage service calls
  • Improved performance

How It Works

When you request a variant, Rails 6.1:

  1. Checks the database for an existing variant record
  2. If found, returns the variant immediately
  3. If not found, generates the variant and stores a database record
  4. Subsequent requests use the cached database record

Usage

Variants work the same way as before:

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

# Rails 6.1 automatically tracks this in the database

Database Schema

Rails 6.1 adds a new table for tracking variants:

# db/migrate/xxx_create_active_storage_variant_records.rb
create_table :active_storage_variant_records do |t|
  t.belongs_to :blob, null: false, index: false
  t.string :variation_digest, null: false

  t.index [:blob_id, :variation_digest], name: "index_active_storage_variant_records_uniqueness", unique: true
  t.foreign_key :active_storage_blobs, column: :blob_id
end

Migration

If you're upgrading to Rails 6.1, run:

rails active_storage:update
rails db:migrate

This will create the active_storage_variant_records table.

Performance Benefits

Reduced Latency

Before Rails 6.1, each variant request could trigger:

  • Storage service lookup
  • Variant generation
  • Storage service upload

With Rails 6.1:

  • Database lookup (fast)
  • Direct variant access if already generated

Example Performance Improvement

# Before: ~200ms per variant request
user.avatar.variant(resize_to_limit: [100, 100])

# After: ~5ms for cached variants
user.avatar.variant(resize_to_limit: [100, 100])

Variant Tracking

You can check if a variant exists:

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

# Check if variant record exists
variant.record.persisted? # => true if variant was generated

Cleaning Up Variants

To clean up unused variants:

# Remove variants for a specific blob
blob.variant_records.destroy_all

# Or use Active Storage's cleanup job
ActiveStorage::VariantRecord.unattached.find_each(&:purge)

Best Practices

  1. Pre-generate common variants: Generate frequently used variants upfront
  2. Monitor variant records: Keep an eye on database growth
  3. Clean up unused variants: Periodically remove unused variant records
  4. Use appropriate variant sizes: Don't generate unnecessarily large variants

Example: Pre-generating Variants

class User < ApplicationRecord
  has_one_attached :avatar

  after_commit :generate_avatar_variants, if: :saved_change_to_avatar_id?

  private

  def generate_avatar_variants
    return unless avatar.attached?

    # Pre-generate common sizes
    avatar.variant(resize_to_limit: [100, 100]).processed
    avatar.variant(resize_to_limit: [200, 200]).processed
    avatar.variant(resize_to_limit: [500, 500]).processed
  end
end

Variant Digest

Rails 6.1 uses a variation_digest to uniquely identify variants:

variant = blob.variant(resize_to_limit: [100, 100])
variant.variation_digest # => "abc123..."

This digest is based on the variant transformation parameters, ensuring consistency.

Comparison with Previous Versions

FeatureBefore Rails 6.1Rails 6.1+
Variant trackingStorage onlyDatabase + Storage
First request latencyHighHigh (generation)
Subsequent requestsMediumLow (cached)
Variant lookupStorage serviceDatabase
PerformanceVariableConsistent

Conclusion

Rails 6.1's database tracking for Active Storage variants significantly improves performance by caching variant information. This feature reduces latency and provides better tracking of generated variants, making Active Storage more efficient for applications with many image variants.

Rails 6.1 tracks Active Storage variant in the database - Abhay Nikam