Automatic Rails migrations
To ensure PlanetScale works well with a traditional Rails development process, we implemented the ability to automatically copy Rails migration metadata as part of our deployment process.
If you are using PlanetScale with a Rails application, go to your database's Settings page in the web app and enable "Automatically copy migration data." Select "Rails/Phoenix" as the migration framework. When enabled, this setting updates the schema_migrations table each time you branch with the latest migration. If disabled, running rake db:migrate will try to run all migrations every time, instead of only the latest one.
Introduction
In this tutorial, you're going to learn how Rails migrations work with the PlanetScale branching and deployment workflows.
Migration tracking works with any migration tool, not just Rails. For other frameworks, specify the migration table name on your database's Settings page.
Prerequisites
Follow the Connect a Rails app tutorial first. By the end, you will have:
- Installed the PlanetScale CLI, Ruby, and the Rails gem
- Created a PlanetScale database named
blog - Started a new Rails app named
blogwith a migration creating aUserstable - Run the first Rails migration
A quick introduction to Rails migrations
Rails tracks an application's migrations in an internal table called schema_migrations. At a high level, running rake db:migrate does the following:
- Rails looks at all of the migration files in your
db/migratedirectory. - Rails queries the
schema_migrationstable to see which migrations have and haven't been run. - Any migration that doesn’t appear in the
schema_migrationstable is considered pending and is executed by this task.
When you merge a deploy request in PlanetScale, the schema_migrations table in main is automatically updated with the migration data from your branch.
Execute a Rails migration on PlanetScale
Rails migrations follow the PlanetScale non-blocking schema change workflow. First, the migration is applied to a development branch, and then the development branch is merged into the main production branch with safe migrations enabled.
Let's add another table to your existing blog schema:
Create an
add-posts-tabledevelopment branch frommainin your database blog:Terminalpscale branch create blog add-posts-tableWhen the branch is ready, you can verify that the
schema_migrationstable is up-to-date withmainby checking for the timestamp of yourCreate Usersmigration file. Your migration will have a different timestamp than the one shown here.Check the timestamp in your codebase:
Terminalls db/migrate20211014210422_create_users.rbConnect to the new branch:
Terminalpscale shell blog add-posts-tableQuery the migration table:
SQLblog/add-posts-table> select * from schema_migrations;+----------------+| version |+----------------+| 20211014210422 |+----------------+Connect your development environment to the new branch:
One way to do this is to create a new password for the
add-posts-tablebranch and updateconfig/database.ymlwith the new username, password, and host. Another is to usepscale connectto establish a secure connection on a local port. Since theadd-posts-tablebranch won't be needed after the migration, let's use thepscale connectproxy.In a separate terminal, establish the connection:
Terminalpscale connect blog add-posts-table --port 3309Then, update
config/database.ymlto connect through the proxy:YAMLdevelopment:<<: *defaultadapter: mysql2database: bloghost: 127.0.0.1port: 3309Create the second Rails migration and call it
CreatePosts:Terminalrails generate migration CreatePostsFind the new migration file in
db/migrateand add a few details for the new Posts table:Rubyclass CreatePosts < ActiveRecord::Migration[7.0]def changecreate_table :posts do |t|t.string :titlet.text :contentt.bool :publishedt.references :usert.timestampsendendendRun the CreatePosts migration:
Terminalrake db:migrateThis command runs the new migration against your
add-posts-tabledevelopment branch.At this point, Rails creates the
poststable and inserts anothertimestampinto theschema_migrationstable on your development branch.You can verify the change in
schema_migrationsyourself:SQLblog/add-posts-table> select * from schema_migrations;+----------------+| version |+----------------+| 20211014210422 || 20220224221753 |+----------------+Open a deploy request for your
add-posts-tablebranch, and deploy your changes tomain.You can complete the deploy request either in the web app or with the
pscale deploy-requestcommand.Terminalpscale deploy-request create blog add-posts-tableTerminalpscale deploy-request deploy blog 1To create the deploy request, PlanetScale looks at the differences between the schemas of
mainandadd-posts-tableand plans acreate tablestatement to add the new table tomain. When you deploy, PlanetScale runs thatcreate tablestatement and copies the second row fromschema_migrationsinadd-posts-tableto theschema_migrationstable inmain.`Verify the changes in your
mainbranch:In a
pscaleshell formainyou can verify that the changes fromadd-posts-tablewere deployed successfully.Terminalpscale shell blog mainSQLblog/|⚠ main ⚠|> show tables;+----------------------+| Tables_in_blog |+----------------------+| posts || schema_migrations || users |+----------------------+blog/|⚠ main ⚠|> select * from schema_migrations;+----------------+| version |+----------------+| 20220223232425 || 20220224221753 |+----------------+
Summary
In this tutorial, we learned how to use the PlanetScale deployment process with the Rails migration workflow.
What's next?
Learn more about how PlanetScale allows you to make schema changes to your production databases without downtime or locking tables.
Need help?
Get help from the PlanetScale support team, or join our GitHub discussion board to see how others are using PlanetScale.