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:
- Checks the database for an existing variant record
- If found, returns the variant immediately
- If not found, generates the variant and stores a database record
- 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
- Pre-generate common variants: Generate frequently used variants upfront
- Monitor variant records: Keep an eye on database growth
- Clean up unused variants: Periodically remove unused variant records
- 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
| Feature | Before Rails 6.1 | Rails 6.1+ |
|---|---|---|
| Variant tracking | Storage only | Database + Storage |
| First request latency | High | High (generation) |
| Subsequent requests | Medium | Low (cached) |
| Variant lookup | Storage service | Database |
| Performance | Variable | Consistent |
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.