Skip to content

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.

Tip

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 PlanetScale's branching and deployment workflows.

Note

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 blog with a migration creating a Users table
  • 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/migrate directory.
  • Rails queries the schema_migrations table to see which migrations have and haven't been run.
  • Any migration that doesn’t appear in the schema_migrations table is considered pending and is executed by this task.
Tip

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.

Let's add another table to your existing blog schema:

  1. Create an add-posts-table development branch from main in your database blog:
Copied
pscale branch create blog add-posts-table

When the branch is ready, you can verify that the schema_migrations table is up-to-date with main by checking for the timestamp of your Create Users migration file. Your migration will have a different timestamp than the one shown here.

Check the timestamp in your codebase:

Copied
ls db/migrate
20211014210422_create_users.rb

Connect to the new branch:

Copied
pscale shell blog add-posts-table

Query the migration table:

Copied
blog/add-posts-table> select * from schema_migrations;
+----------------+
| version |
+----------------+
| 20211014210422 |
+----------------+
  1. Connect your development environment to the new branch:

One way to do this is to create a new password for the add-posts-table branch and update config/database.yml with the new username, password, and host. Another is to use pscale connect to establish a secure connection on a local port. Since the add-posts-table branch won't be needed after the migration, let's use the pscale connect proxy.

In a separate terminal, establish the connection:

Copied
pscale connect blog add-posts-table --port 3309

Then, update config/database.yml to connect through the proxy:

Copied
development:
<<: *default
adapter: mysql2
database: blog
host: 127.0.0.1
port: 3309
  1. Create the second Rails migration and call it CreatePosts:
Copied
rails generate migration CreatePosts

Find the new migration file in db/migrate and add a few details for the new Posts table:

Copied
class CreatePosts < ActiveRecord::Migration[7.0]
def change
create_table :posts do |t|
t.string :title
t.text :content
t.bool :published
t.references :user
t.timestamps
end
end
end
  1. Run the CreatePosts migration:
Copied
rake db:migrate

This command runs the new migration against your add-posts-table development branch.

At this point, Rails creates the posts table and inserts another timestamp into the schema_migrations table on your development branch.

You can verify the change in schema_migrations yourself:

Copied
blog/add-posts-table> select * from schema_migrations;
+----------------+
| version |
+----------------+
| 20211014210422 |
| 20220224221753 |
+----------------+
  1. Open a deploy request for your add-posts-table branch, and deploy your changes to main.

You can complete the deploy request either in the web app or with the pscale deploy-request command.

Copied
pscale deploy-request create blog add-posts-table
Copied
pscale deploy-request deploy blog 1

To create the deploy request, PlanetScale looks at the differences between the schemas of main and add-posts-table and plans a create table statement to add the new table to main. When you deploy, PlanetScale runs that create table statement and copies the second row from schema_migrations in add-posts-table to the schema_migrations table in main.`

  1. Verify the changes in your main branch:

In a pscale shell for main you can verify that the changes from add-posts-table were deployed successfully.

Copied
pscale shell blog main
Copied
blog/|⚠ 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 PlanetScale's 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 PlanetScale's support team, or join our GitHub Discussion board to see how others are using PlanetScale.

Was this page useful?
Last updated on May 3, 2022
Help us improve this page
PrivacyTerms© 2022 PlanetScale Inc.