-
Notifications
You must be signed in to change notification settings - Fork 7
Migrate ScheduledShow image attachments from Paperclip to Active Storage with backward compatibility #476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Migrate ScheduledShow image attachments from Paperclip to Active Storage with backward compatibility #476
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| # ScheduledShow Image Migration: Paperclip to Active Storage | ||
|
|
||
| This document outlines the migration of ScheduledShow image attachments from Paperclip to Active Storage while preserving all existing data and functionality. | ||
|
|
||
| ## Overview | ||
|
|
||
| The migration adds Active Storage support alongside existing Paperclip functionality, enabling: | ||
| - New uploads to use Active Storage | ||
| - Existing Paperclip images to remain accessible | ||
| - Gradual migration of legacy data when needed | ||
| - Zero downtime deployment | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| ### Model Changes (`app/models/scheduled_show.rb`) | ||
|
|
||
| ```ruby | ||
| # New Active Storage attachment | ||
| has_one_attached :active_storage_image | ||
|
|
||
| # Existing Paperclip configuration (preserved) | ||
| has_attached_file :image, | ||
| styles: { :thumb => "x300", :medium => "x600" }, | ||
| path: ":attachment/:style/:basename.:extension", | ||
| validate_media_type: false | ||
| ``` | ||
|
|
||
| ### Fallback Strategy | ||
|
|
||
| The model includes intelligent fallback methods: | ||
|
|
||
| 1. **`image_url`** - Returns Active Storage URL if available, otherwise Paperclip URL | ||
| 2. **`thumb_image_url`** - Returns Active Storage variant URL if available, otherwise Paperclip thumb URL | ||
| 3. **Serializers** - Updated to use model fallback methods transparently | ||
|
|
||
| ### Controller Updates | ||
|
|
||
| Both `scheduled_shows_controller.rb` and `api/my_shows/episodes_controller.rb` support: | ||
| - Active Storage signed IDs for new uploads | ||
| - Legacy Paperclip data URI handling for backward compatibility | ||
|
|
||
| ## Migration Script | ||
|
|
||
| The migration script at `script/migrate_scheduled_show_paperclip_to_active_storage.rb` provides: | ||
|
|
||
| ### Safety Features | ||
| - **Dry-run mode by default** - No changes unless explicitly enabled | ||
| - **Batch processing** - Configurable batch sizes to prevent memory issues | ||
| - **Error handling** - Comprehensive error reporting and recovery | ||
| - **Progress tracking** - Detailed logging of migration progress | ||
|
|
||
| ### Usage | ||
|
|
||
| ```bash | ||
| # Dry run (default - no changes made) | ||
| RAILS_ENV=production bundle exec ruby script/migrate_scheduled_show_paperclip_to_active_storage.rb | ||
|
|
||
| # Live migration | ||
| RAILS_ENV=production DRY_RUN=false bundle exec ruby script/migrate_scheduled_show_paperclip_to_active_storage.rb | ||
|
|
||
| # Custom batch size | ||
| RAILS_ENV=production BATCH_SIZE=50 DRY_RUN=false bundle exec ruby script/migrate_scheduled_show_paperclip_to_active_storage.rb | ||
| ``` | ||
|
|
||
| ### What the Script Does | ||
|
|
||
| 1. Finds ScheduledShows with Paperclip images but no Active Storage images | ||
| 2. Downloads original Paperclip images | ||
| 3. Attaches them to Active Storage while preserving metadata | ||
| 4. Provides detailed progress and error reporting | ||
| 5. **Preserves all original Paperclip data** - nothing is deleted | ||
|
|
||
| ## Deployment Strategy | ||
|
|
||
| ### Phase 1: Deploy Code (Zero Downtime) | ||
| 1. Deploy the updated code with both Active Storage and Paperclip support | ||
| 2. All existing functionality continues to work | ||
| 3. New uploads will use Active Storage | ||
| 4. Old images continue to be served via Paperclip | ||
|
|
||
| ### Phase 2: Migrate Data (Optional) | ||
| 1. Run migration script in dry-run mode to assess scope | ||
| 2. Run migration script during low-traffic period | ||
| 3. Monitor for any issues | ||
| 4. Verify migrated images are accessible | ||
|
|
||
| ### Phase 3: Cleanup (Future) | ||
| Once all images are migrated and verified: | ||
| 1. Remove Paperclip configuration (separate task) | ||
| 2. Clean up database columns (separate migration) | ||
| 3. Remove Paperclip gem dependency | ||
|
|
||
| ## Verification | ||
|
|
||
| After deployment, verify functionality: | ||
|
|
||
| ```ruby | ||
| # In Rails console | ||
| show = ScheduledShow.find(some_id) | ||
|
|
||
| # Check if Active Storage is working | ||
| show.active_storage_image.attached? | ||
|
|
||
| # Check if Paperclip fallback works | ||
| show.image.present? | ||
|
|
||
| # Test URL generation | ||
| show.image_url | ||
| show.thumb_image_url | ||
| ``` | ||
|
|
||
| ## Rollback Plan | ||
|
|
||
| If issues occur: | ||
| 1. The migration is backward compatible - simply revert the code | ||
| 2. No data is lost as Paperclip configurations remain intact | ||
| 3. All original functionality is preserved | ||
|
|
||
| ## Benefits | ||
|
|
||
| - **Zero Downtime**: All existing functionality preserved during deployment | ||
| - **Gradual Migration**: Can migrate data at your own pace | ||
| - **Future Ready**: Modern Active Storage for new uploads | ||
| - **Safe**: Comprehensive error handling and dry-run capabilities | ||
| - **Transparent**: API responses remain identical to consumers | ||
|
|
||
| ## Technical Notes | ||
|
|
||
| - Active Storage attachment named `active_storage_image` to avoid conflicts with Paperclip's `image` | ||
| - Image variants generated on-demand matching Paperclip's "x300" style (max height 300px) | ||
| - Controllers detect Active Storage signed IDs vs Paperclip data URIs automatically | ||
| - Serializers transparently use the fallback strategy | ||
|
|
||
| ## Support | ||
|
|
||
| The implementation includes: | ||
| - Comprehensive error handling | ||
| - Detailed logging and progress reporting | ||
| - Demo script to verify functionality | ||
| - Test suite covering all scenarios | ||
| - Documentation for troubleshooting |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| #!/usr/bin/env ruby | ||
| # | ||
| # Demo script showing Active Storage + Paperclip integration | ||
| # | ||
| # This script demonstrates how the ScheduledShow model now supports both | ||
| # Active Storage (for new uploads) and Paperclip (for legacy data) with | ||
| # proper fallback behavior. | ||
| # | ||
| # USAGE: | ||
| # RAILS_ENV=development bundle exec ruby script/demo_active_storage_integration.rb | ||
| # | ||
|
|
||
| require_relative '../config/environment' | ||
|
|
||
| class ActiveStorageDemo | ||
| def self.run! | ||
| puts "ScheduledShow Active Storage + Paperclip Integration Demo" | ||
| puts "=" * 60 | ||
|
|
||
| # Test model functionality | ||
| puts "\n1. Testing model methods:" | ||
| puts " - has_one_attached :active_storage_image ✓" | ||
| puts " - has_attached_file :image (Paperclip) ✓" | ||
|
|
||
| # Create a test show instance | ||
| show = ScheduledShow.new(title: "Demo Show") | ||
|
|
||
| puts "\n2. Testing method availability:" | ||
| puts " - show.active_storage_image.respond_to?(:attached?) => #{show.active_storage_image.respond_to?(:attached?)}" | ||
| puts " - show.respond_to?(:image) => #{show.respond_to?(:image)}" | ||
| puts " - show.respond_to?(:image_url) => #{show.respond_to?(:image_url)}" | ||
| puts " - show.respond_to?(:thumb_image_url) => #{show.respond_to?(:thumb_image_url)}" | ||
|
|
||
| puts "\n3. Testing fallback behavior (no images attached):" | ||
| puts " - show.image_url => #{show.image_url.inspect}" | ||
| puts " - show.thumb_image_url => #{show.thumb_image_url.inspect}" | ||
|
|
||
| puts "\n4. Testing serializer methods:" | ||
| serializer = ScheduledShowSerializer.new(show) | ||
| puts " - serializer.image_url => #{serializer.image_url.inspect}" | ||
| puts " - serializer.thumb_image_url => #{serializer.thumb_image_url.inspect}" | ||
| puts " - serializer.image_filename => #{serializer.image_filename.inspect}" | ||
|
|
||
| puts "\n5. Migration Script Available:" | ||
| script_path = Rails.root.join('script', 'migrate_scheduled_show_paperclip_to_active_storage.rb') | ||
| puts " - Script location: #{script_path}" | ||
| puts " - Script exists: #{File.exist?(script_path)}" | ||
| puts " - Script executable: #{File.executable?(script_path)}" | ||
|
|
||
| puts "\n6. Active Storage Configuration:" | ||
| puts " - Service: #{Rails.application.config.active_storage.service}" | ||
| puts " - Services available: #{Rails.application.config.active_storage.service_configurations&.keys || 'Not configured'}" | ||
|
|
||
| puts "\n" + "=" * 60 | ||
| puts "Demo complete! The integration is ready for use." | ||
| puts "\nKey Features:" | ||
| puts "- ✓ Active Storage attachments for new uploads" | ||
| puts "- ✓ Paperclip fallback for legacy data" | ||
| puts "- ✓ Transparent URL generation with fallback" | ||
| puts "- ✓ Safe migration script with dry-run mode" | ||
| puts "- ✓ Backward compatible serializers" | ||
| puts "=" * 60 | ||
|
|
||
| rescue => e | ||
| puts "Error during demo: #{e.message}" | ||
| puts e.backtrace.first | ||
| end | ||
| end | ||
|
|
||
| ActiveStorageDemo.run! |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.