Rails Upgrade Analyzer
Analyze the current Rails application and provide a comprehensive upgrade assessment with selective file merging.
Step 1: Verify Rails Application
Check that we're in a Rails application by looking for these files:
Gemfile(must exist and contain 'rails')config/application.rb(Rails application config)config/environment.rb(Rails environment)
If any of these are missing or don't indicate a Rails app, stop and inform the user this doesn't appear to be a Rails application.
Step 2: Get Current Rails Version
Extract the current Rails version from:
- First, check
Gemfile.lockfor the exact installed version (look forrails (x.y.z)) - If not found, check
Gemfilefor the version constraint
Report the exact current version (e.g., 7.1.3).
Step 3: Find Latest Rails Version
Use the GitHub CLI to fetch the latest Rails release:
gh api repos/rails/rails/releases/latest --jq '.tag_name'
This returns the latest stable version tag (e.g., v8.0.1). Strip the 'v' prefix for comparison.
Also check recent tags to understand the release landscape:
gh api repos/rails/rails/tags --jq '.[0:10] | .[].name'
Step 4: Determine Upgrade Type
Compare current and latest versions to classify the upgrade:
- Patch upgrade: Same major.minor, different patch (e.g., 7.1.3 → 7.1.5)
- Minor upgrade: Same major, different minor (e.g., 7.1.3 → 7.2.0)
- Major upgrade: Different major version (e.g., 7.1.3 → 8.0.0)
Step 5: Fetch Upgrade Guide
Use WebFetch to get the official Rails upgrade guide:
URL: https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
Look for sections relevant to the version jump. The guide is organized by target version with sections like:
- "Upgrading from Rails X.Y to Rails X.Z"
- Breaking changes
- Deprecation warnings
- Configuration changes
- Required migrations
Extract and summarize the relevant sections for the user's specific upgrade path.
Step 6: Fetch Rails Diff
Use WebFetch to get the diff between versions from railsdiff.org:
URL: https://railsdiff.org/{current_version}/{target_version}
For example: https://railsdiff.org/7.1.3/8.0.0
This shows:
- Changes to default configuration files
- New files that need to be added
- Modified initializers
- Updated dependencies
- Changes to bin/ scripts
Summarize the key file changes.
Step 7: Check JavaScript Dependencies
Rails applications often include JavaScript packages that should be updated alongside Rails. Check for and report on these dependencies.
7.1: Identify JS Package Manager
Check which package manager the app uses:
# Check for package.json (npm/yarn)
ls package.json 2>/dev/null
# Check for importmap (Rails 7+)
ls config/importmap.rb 2>/dev/null
7.2: Check Rails-Related JS Packages
If package.json exists, check for these Rails-related packages:
# Extract current versions of Rails-related packages
cat package.json | grep -E '"@hotwired/|"@rails/|"stimulus"|"turbo-rails"' || echo "No Rails JS packages found"
Key packages to check:
| Package | Purpose | Version Alignment |
|---|---|---|
@hotwired/turbo-rails | Turbo Drive/Frames/Streams | Should match Rails version era |
@hotwired/stimulus | Stimulus JS framework | Generally stable across Rails versions |
@rails/actioncable | WebSocket support | Should match Rails version |
@rails/activestorage | Direct uploads | Should match Rails version |
@rails/actiontext | Rich text editing | Should match Rails version |
@rails/request.js | Rails UJS replacement | Should match Rails version era |
7.3: Check for Updates
For npm/yarn projects, check for available updates:
# Using npm
npm outdated @hotwired/turbo-rails @hotwired/stimulus @rails/actioncable @rails/activestorage 2>/dev/null
# Or check latest versions directly
npm view @hotwired/turbo-rails version 2>/dev/null
npm view @rails/actioncable version 2>/dev/null
7.4: Check Importmap Pins (if applicable)
If the app uses importmap-rails, check config/importmap.rb for pinned versions:
cat config/importmap.rb | grep -E 'pin.*turbo|pin.*stimulus|pin.*@rails' || echo "No importmap pins found"
To update importmap pins:
bin/importmap pin @hotwired/turbo-rails
bin/importmap pin @hotwired/stimulus
7.5: JS Dependency Summary
Include in the upgrade summary:
### JavaScript Dependencies
**Package Manager**: [npm/yarn/importmap/none]
| Package | Current | Latest | Action |
|---------|---------|--------|--------|
| @hotwired/turbo-rails | 8.0.4 | 8.0.12 | Update recommended |
| @rails/actioncable | 7.1.0 | 8.0.0 | Update with Rails |
| ... | ... | ... | ... |
**Recommended JS Updates:**
- Run `npm update @hotwired/turbo-rails` (or yarn equivalent)
- Run `npm update @rails/actioncable @rails/activestorage` to match Rails version
Step 8: Generate Upgrade Summary
Provide a comprehensive summary including all findings from Steps 1-7:
Version Information
- Current version: X.Y.Z
- Latest version: A.B.C
- Upgrade type: [Patch/Minor/Major]
Upgrade Complexity Assessment
Rate the upgrade as Small, Medium, or Large based on:
| Factor | Small | Medium | Large |
|---|---|---|---|
| Version jump | Patch only | Minor version | Major version |
| Breaking changes | None | Few, well-documented | Many, significant |
| Config changes | Minimal | Moderate | Extensive |
| Deprecations | None active | Some to address | Many requiring refactoring |
| Dependencies | Compatible | Some updates needed | Major dependency updates |
Key Changes to Address
List the most important changes the user needs to handle:
- Configuration file updates
- Deprecated methods/features to update
- New required dependencies
- Database migrations needed
- Breaking API changes
Recommended Upgrade Steps
- Update test suite and ensure passing
- Review deprecation warnings in current version
- Update Gemfile with new Rails version
- Run
bundle update rails - Update JavaScript dependencies (see JS Dependencies section)
- DO NOT run
rails app:updatedirectly - use the selective merge process below - Run database migrations
- Run test suite
- Review and update deprecated code
Resources
- Rails Upgrade Guide: https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
- Rails Diff: https://railsdiff.org/{current}/{target}
- Release Notes: https://github.com/rails/rails/releases/tag/v{target}
Step 9: Selective File Update (replaces rails app:update)
IMPORTANT: Do NOT run rails app:update as it overwrites files without considering local customizations. Instead, follow this selective merge process:
9.1: Detect Local Customizations
Before any upgrade, identify files with local customizations:
# Check for uncommitted changes
git status
# List config files that differ from a fresh Rails app
# These are the files we need to be careful with
git diff HEAD --name-only -- config/ bin/ public/
Create a mental list of files in these categories:
- Custom config files: Files with project-specific settings (i18n, mailer, etc.)
- Modified bin scripts: Scripts with custom behavior (bin/dev with foreman, etc.)
- Standard files: Files that haven't been customized
9.2: Analyze Required Changes from Railsdiff
Based on the railsdiff output from Step 6, categorize each changed file:
| Category | Action | Example |
|---|---|---|
| New files | Create directly | config/initializers/new_framework_defaults_X_Y.rb |
| Unchanged locally | Safe to overwrite | public/404.html (if not customized) |
| Customized locally | Manual merge needed | config/application.rb, bin/dev |
| Comment-only changes | Usually skip | Minor comment updates in config files |
9.3: Create Upgrade Plan
Present the user with a clear upgrade plan:
## Upgrade Plan: Rails X.Y.Z → A.B.C
### New Files (will be created):
- config/initializers/new_framework_defaults_A_B.rb
- bin/ci (new CI script)
### Safe to Update (no local customizations):
- public/400.html
- public/404.html
- public/500.html
### Needs Manual Merge (local customizations detected):
- config/application.rb
└─ Local: i18n configuration
└─ Rails: [describe new Rails changes if any]
- config/environments/development.rb
└─ Local: letter_opener mailer config
└─ Rails: [describe new Rails changes]
- bin/dev
└─ Local: foreman + Procfile.dev setup
└─ Rails: changed to simple ruby script
### Skip (comment-only or irrelevant changes):
- config/puma.rb (only comment changes)
9.4: Execute Upgrade Plan
After user confirms the plan:
For New Files:
Create them directly using the content from railsdiff or by extracting from a fresh Rails app:
# Generate a temporary fresh Rails app to extract new files
cd /tmp && rails new rails_template --skip-git --skip-bundle
# Then copy needed files
Or use the Rails generator for specific files:
bin/rails app:update:configs # Only updates config files, still interactive
For Safe Updates:
Overwrite these files as they have no local customizations.
For Manual Merges:
For each file needing merge, show the user:
- Current local version (their customizations)
- New Rails default (from railsdiff)
- Suggested merged version that:
- Keeps all local customizations
- Adds only essential new Rails functionality
- Removes deprecated settings
Example merge for config/application.rb:
# KEEP local customizations:
config.i18n.available_locales = [:de, :en]
config.i18n.default_locale = :de
config.i18n.fallbacks = [:en]
# ADD new Rails 8.1 settings if needed:
# (usually none required - new defaults come via new_framework_defaults file)
9.5: Handle Active Storage Migrations
After file updates, run any new migrations:
bin/rails db:migrate
Check for new migrations that were added:
ls -la db/migrate/ | tail -10
9.6: Verify Upgrade
After completing the merge:
-
Start the Rails server and check for errors:
bin/dev # or bin/rails server -
Check the Rails console:
bin/rails console -
Run the test suite:
bin/rails test -
Review deprecation warnings in logs
Step 10: Finalize Framework Defaults
After verifying the app works:
- Review
config/initializers/new_framework_defaults_X_Y.rb - Enable each new default one by one, testing after each
- Once all defaults are enabled and tested, update
config/application.rb:config.load_defaults X.Y # Update to new version - Delete the
new_framework_defaults_X_Y.rbfile
Error Handling
- If
ghCLI is not authenticated, instruct the user to rungh auth login - If railsdiff.org doesn't have the exact versions, try with major.minor.0 versions
- If the app is already on the latest version, congratulate the user and note any upcoming releases
- If local customizations would be lost, ALWAYS stop and show the user what would be overwritten before proceeding
Key Principles
- Never overwrite without checking - Always check for local customizations first
- Preserve user intent - Local customizations exist for a reason
- Minimal changes - Only add what's necessary for the new Rails version
- Transparency - Show the user exactly what will change before doing it
- Reversibility - User should be able to
git checkoutto restore if needed