Stop database headaches when switching Git branches in Rails
Keep your database schema perfectly synchronized across Git branches, eliminate broken tests and schema conflicts, and save wasted hours on phantom migrations.
- Zero Manual Work: Switch branches freely - phantom migrations roll back automatically
- No More Schema Conflicts: Clean
schema.rb/structure.sqldiffs every time, no irrelevant changes - Error Prevention: Eliminates
ActiveRecord::NotNullViolationand similar errors when switching branches - Time Savings: Stop hunting down which branch has the problematic migration
- Team Productivity: Everyone stays focused on coding, not database maintenance
- Staging/Sandbox Sync: Keep staging and sandbox databases aligned with your current branch code
- Visual Management: Web UI to view and manage migrations across all databases
And you get all of that with zero changes to your workflow!
Before ActualDbSchema:
- Work on Branch A β Add migration β Run migration
- Switch to Branch B β Code breaks with database errors
- Manually find and rollback the "phantom" migration
- Deal with irrelevant
schema.rbdiffs - Repeat this tedious process constantly
After ActualDbSchema:
- Work on any branch β Add migrations as usual
- Switch branches freely β Everything just works
- Focus on building features, not fixing database issues
- Phantom Migration Detection: Automatically identifies migrations from other branches
- Smart Rollback: Rolls back phantom migrations in correct dependency order
- Irreversible Migration Handling: Safely handles and reports irreversible migrations
- Multi-Database Support: Works seamlessly with multiple database configurations
- Schema Format Agnostic: Supports both
schema.rbandstructure.sql
- Automatic Rollback on Migration: Phantom migrations roll back when running
db:migrate - Git Hook Integration: Optional automatic rollback when switching branches
- Zero Configuration: Works out of the box with sensible defaults
- Custom Migration Storage: Configurable location for storing executed migrations
- Migration Dashboard: Visual overview of all migrations across databases
- Phantom Migration Browser: Easy-to-use interface for viewing phantom migrations
- One-Click Rollback: Rollback individual or all phantom migrations via web UI
- Broken Version Cleanup: Identify and remove orphaned migration records
- Schema Diff Viewer: Visual diff of schema changes with migration annotations
- Console Migrations: Run migration commands directly in Rails console
- Schema Diff Analysis: Annotated diffs showing which migrations caused changes
- Migration Search & Filter: Find specific migrations across all databases
- Detailed Migration Info: View migration status, branch, and database information
- Multi-Tenant Compatible: Works with apartment gem and similar multi-tenant setups
- Environment Flexibility: Enable/disable features per environment
- Team Synchronization: Keeps all team members' databases in sync
- CI/CD Friendly: No interference with deployment pipelines
- Manual Rollback Mode: Disable automatic rollback for full manual control
- Selective Rollback: Choose which phantom migrations to rollback
- Interactive Mode: Step-by-step confirmation for each rollback operation
- Rake Task Integration: Full set of rake tasks for command-line management
Add to your Gemfile:
group :development do
gem "actual_db_schema"
endInstall and configure:
bundle install
rails actual_db_schema:installThat's it! Now just run rails db:migrate as usual - phantom migrations roll back automatically.
This gem stores all run migrations with their code in the tmp/migrated folder. Whenever you perform a schema dump, it rolls back the phantom migrations.
The phantom migrations list is the difference between the migrations you've executed (in the tmp/migrated folder) and the current ones (in the db/migrate folder).
Therefore, all you do is run rails db:migrate in your current branch. actual_db_schema will ensure the DB schema is up-to-date. You'll never have an inaccurate schema.rb file again.
Add this line to your application's Gemfile:
group :development do
gem "actual_db_schema"
endAnd then execute:
$ bundle install
If you cannot commit changes to the repo or Gemfile, consider the local Gemfile installation described in this post.
Next, generate your ActualDbSchema initializer file by running:
rails actual_db_schema:installThis will create a config/initializers/actual_db_schema.rb file that lists all available configuration options, allowing you to customize them as needed. The installation process will also prompt you to install the post-checkout Git hook, which automatically rolls back phantom migrations when switching branches. If enabled, this hook will run the schema actualization rake task every time you switch branches, which can slow down branch changes. Therefore, you might not always want this automatic actualization on every switch; in that case, running rails db:migrate manually provides a faster, more controlled alternative.
For more details on the available configuration options, see the sections below.
Just run rails db:migrate inside the current branch. It will roll back all phantom migrations for all configured databases in your database.yml.
Warning
This solution implies that all migrations are reversible. The irreversible migrations should be solved manually. At the moment, the gem ignores them. You will see warnings in the terminal for each irreversible migrations.
The gem offers the following rake tasks that can be manually run according to your preferences:
rails db:rollback_branches- run it to manually rolls back phantom migrations.rails db:rollback_branches:manual- run it to manually rolls back phantom migrations one by one.rails db:phantom_migrations- displays a list of phantom migrations.
By default, actual_db_schema stores all run migrations in the tmp/migrated folder. However, if you want to change this location, you can configure it in two ways:
Set the environment variable ACTUAL_DB_SCHEMA_MIGRATED_FOLDER to your desired folder path:
export ACTUAL_DB_SCHEMA_MIGRATED_FOLDER="custom/migrated"Add the following line to your initializer file (config/initializers/actual_db_schema.rb):
config.migrated_folder = Rails.root.join("custom", "migrated")Access the migration management UI at:
http://localhost:3000/rails/phantom_migrations
View and manage:
- Migration Overview: See all executed migrations with their status, branch, and database
- Phantom Migrations: Identify migrations from other branches that need rollback
- Migration Source Code: Browse the source code of every migration ever run (including the phantom ones)
- One-Click Actions: Rollback or migrate individual migrations directly from the UI
- Broken Versions: Detect and clean up orphaned migration records safely
- Schema Diffs: Visual diff of schema changes annotated with their source migrations
By default, the UI is enabled in the development environment. If you prefer to enable the UI for another environment, you can do so in two ways:
Set the environment variable ACTUAL_DB_SCHEMA_UI_ENABLED to true:
export ACTUAL_DB_SCHEMA_UI_ENABLED=trueAdd the following line to your initializer file (config/initializers/actual_db_schema.rb):
config.ui_enabled = trueWith this option, the UI can be disabled for all environments or be enabled in specific ones.
By default, the automatic rollback of migrations is enabled. If you prefer to perform manual rollbacks, you can disable the automatic rollback in two ways:
Set the environment variable ACTUAL_DB_SCHEMA_AUTO_ROLLBACK_DISABLED to true:
export ACTUAL_DB_SCHEMA_AUTO_ROLLBACK_DISABLED=trueAdd the following line to your initializer file (config/initializers/actual_db_schema.rb):
config.auto_rollback_disabled = trueBy default, the automatic rollback of migrations on branch switch is disabled. If you prefer to automatically rollback phantom migrations whenever you switch branches with git checkout, you can enable it in two ways:
Set the environment variable ACTUAL_DB_SCHEMA_GIT_HOOKS_ENABLED to true:
export ACTUAL_DB_SCHEMA_GIT_HOOKS_ENABLED=trueAdd the following line to your initializer file (config/initializers/actual_db_schema.rb):
config.git_hooks_enabled = trueAfter enabling Git hooks in your configuration, run the rake task to install the post-checkout hook:
rake actual_db_schema:install_git_hooksThis task will prompt you to choose one of the three options:
- Rollback phantom migrations with
db:rollback_branches - Migrate up to the latest schema with
db:migrate - Skip installing git hook
Based on your selection, a post-checkout hook will be installed or updated in your .git/hooks folder.
If your application leverages multiple schemas for multi-tenancy β such as those implemented by the apartment gem or similar solutions β you can configure ActualDbSchema to handle migrations across all schemas. To do so, add the following configuration to your initializer file (config/initializers/actual_db_schema.rb):
config.multi_tenant_schemas = -> { # list of all active schemas }config.multi_tenant_schemas = -> { ["public", "tenant1", "tenant2"] }If schema.rb generates a diff, it can be helpful to find out which migrations caused the changes. This helps you decide whether to resolve the diff on your own or discuss it with your teammates to determine the next steps. The diff_schema_with_migrations Rake task generates a diff of the schema.rb file, annotated with the migrations responsible for each change. This makes it easier to trace which migration introduced a specific schema modification, enabling faster and more informed decision-making regarding how to handle the diff.
By default, the task uses db/schema.rb and db/migrate as the schema and migrations paths. You can also provide custom paths as arguments.
Alternatively, if you use Web UI, you can see this diff at http://localhost:3000/rails/schema. This way is often more convenient than running the Rake task manually.
Run the task with default paths:
rake actual_db_schema:diff_schema_with_migrationsRun the task with custom paths:
rake actual_db_schema:diff_schema_with_migrations[path/to/custom_schema.rb, path/to/custom_migrations]Sometimes, it's necessary to modify the database without creating migration files. This can be useful for fixing a corrupted schema, conducting experiments (such as adding and removing indexes), or quickly adjusting the schema in development. This gem allows you to run the same commands used in migrations directly in the Rails console.
By default, Console Migrations is disabled. You can enable it in two ways:
Set the environment variable ACTUAL_DB_SCHEMA_CONSOLE_MIGRATIONS_ENABLED to true:
export ACTUAL_DB_SCHEMA_CONSOLE_MIGRATIONS_ENABLED=trueAdd the following line to your initializer file (config/initializers/actual_db_schema.rb):
config.console_migrations_enabled = trueOnce enabled, you can run migration commands directly in the Rails console:
# Create a new table
create_table :posts do |t|
t.string :title
end
# Add a column
add_column :users, :age, :integer
# Remove an index
remove_index :users, :email
# Rename a column
rename_column :users, :username, :handleA migration is considered broken if it has been migrated in the database but the corresponding migration file is missing. This functionality allows you to safely delete these broken versions from the database to keep it clean.
You can delete broken migrations using either of the following methods:
Navigate to the following URL in your web browser:
http://localhost:3000/rails/broken_versions
This page lists all broken versions and provides an option to delete them.
To delete all broken migrations, run:
rake actual_db_schema:delete_broken_versionsTo delete specific migrations, pass the migration version(s) and optionally a database:
rake actual_db_schema:delete_broken_versions[<version>, <version>]<version>β The migration version(s) to delete (space-separated if multiple).<database>(optional) β Specify a database if using multiple databases.
# Delete all broken migrations
rake actual_db_schema:delete_broken_versions
# Delete specific migrations
rake actual_db_schema:delete_broken_versions["20250224103352 20250224103358"]
# Delete specific migrations from a specific database
rake actual_db_schema:delete_broken_versions["20250224103352 20250224103358", "primary"]After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install.
To release a new version do the following in the order:
- update the version number in
version.rb; - update the CHANGELOG;
bundle installto updateGemfile.lock;- make the commit and push;
- run
bundle exec rake release. This will create a git tag for the version, push git commits and the created tag, and push the.gemfile to rubygems.org; - announce the new release on GitHub;
- close the milestone on GitHub.
The following versions can be specifically tested using Appraisal
- 6.0
- 6.1
- 7.0
- 7.1
- edge
To run tests with a specific version of Rails using Appraisal:
- Run all tests with Rails 6.0:
bundle exec appraisal rails.6.0 rake test
- Run tests for a specific file:
bundle exec appraisal rails.6.0 rake test TEST=test/rake_task_test.rb
- Run a specific test:
bundle exec appraisal rails.6.0 rake test TEST=test/rake_task_test.rb TESTOPTS="--name=/db::db:rollback_branches#test_0003_keeps/"
By default, rake test runs tests using SQLite3. To explicitly run tests with SQLite3, PostgreSQL, or MySQL, you can use the following tasks:
- Run tests with
SQLite3:bundle exec rake test:sqlite3 - Run tests with
PostgreSQL(requires Docker):bundle exec rake test:postgresql - Run tests with
MySQL(requires Docker):bundle exec rake test:mysql2 - Run tests for all supported adapters:
bundle exec rake test:all
Bug reports and pull requests are welcome on GitHub at https://github.com/widefix/actual_db_schema. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the ActualDbSchema project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.