Ruby

ActiveRecord (Rails) migrations, drawn as a database diagram

Ruby migration classes from db/migrate, with change or up and down methods. SchemaDrawer runs ActiveRecord 8.1 on Ruby 3.4 against a throw-away database of the engine you choose and returns an SVG of the schema it produces.

What to upload

Upload db/migrate: files named <version>_<title>.rb, each holding a class named after the title that extends ActiveRecord::Migration[x.y]. Nested directories are found too.

The sample below is the PetClinic schema written for ActiveRecord (Rails), one of the sets SchemaDrawer's own tests draw on every engine:

db/migrate/
├── 001_create_owners_and_pets.rb
├── 002_create_vets.rb
└── 003_create_visits.rb

Formats

Ruby migration files.

How it runs

ActiveRecord::MigrationContext#migrate, without a Rails application around it. The database is a fresh PostgreSQL, MySQL, MariaDB, SQL Server, Oracle or SQLite container in the version you ask for; nothing of yours is touched.

Databases you can draw ActiveRecord (Rails) on

PostgreSQL 10, 11, 12, 13, 14, 15, 16, 17, 18 MySQL 8.0, 8.4, 9 MariaDB 10.6, 11.4, 11.8, 12 SQL Server 2017, 2019, 2022, 2025 Oracle SQLite

Not offered for ActiveRecord (Rails): Oracle. The tool ships no driver for it, so nothing could run.

At a glance

Runs
ActiveRecord 8.1 on Ruby 3.4, with the pg, mysql2, tiny_tds and sqlite3 gems
API value
migrationType=ACTIVE_RECORD
Engines
5 of 6: PostgreSQL, MySQL, MariaDB, SQL Server, SQLite
Output
SVG diagram with tables, columns and types, primary and foreign keys
Price
Free today; enterprise plans are coming
Example

The PetClinic schema in ActiveRecord (Rails)

Owners, pets, types, vets, specialties and visits: the same seven tables every sample set on this site creates. These are the exact files the tests upload.

class CreateOwnersAndPets < ActiveRecord::Migration[8.1]
  def change
    # `id: :integer, default: nil` is the only spelling that yields a plain INT
    # primary key on both engines. Plain `id: :integer` yields `serial` on
    # PostgreSQL and `int AUTO_INCREMENT` on MySQL; mentioning :default at all
    # is what switches the auto-increment behaviour off.
    create_table :owners, id: :integer, default: nil do |t|
      t.string :first_name, limit: 50, null: false
      t.string :last_name,  limit: 50, null: false
      t.string :address,    limit: 255
      t.string :city,       limit: 80
      t.string :telephone,  limit: 20
    end

    create_table :types, id: :integer, default: nil do |t|
      t.string :name, limit: 80, null: false
    end

    create_table :pets, id: :integer, default: nil do |t|
      t.string  :name, limit: 50, null: false
      t.date    :birth_date
      t.integer :type_id,  null: false
      t.integer :owner_id, null: false
    end

    add_foreign_key :pets, :types,  column: :type_id,  name: "fk_pets_types"
    add_foreign_key :pets, :owners, column: :owner_id, name: "fk_pets_owners"
  end
end
class CreateVets < ActiveRecord::Migration[8.1]
  def change
    create_table :vets, id: :integer, default: nil do |t|
      t.string :first_name, limit: 50, null: false
      t.string :last_name,  limit: 50, null: false
    end

    create_table :specialties, id: :integer, default: nil do |t|
      t.string :name, limit: 80, null: false
    end

    # A real composite primary key (Rails 7.1+): no surrogate `id` column is
    # added, and the columns come out in the order of the block.
    create_table :vet_specialties, primary_key: [:vet_id, :specialty_id] do |t|
      t.integer :vet_id,       null: false
      t.integer :specialty_id, null: false
    end

    add_foreign_key :vet_specialties, :vets,        column: :vet_id,       name: "fk_vet_specialties_vets"
    add_foreign_key :vet_specialties, :specialties, column: :specialty_id, name: "fk_vet_specialties_specialties"
  end
end
class CreateVisits < ActiveRecord::Migration[8.1]
  def change
    create_table :visits, id: :integer, default: nil do |t|
      t.integer :pet_id, null: false
      t.date    :visit_date
      t.string  :description, limit: 255
    end

    add_foreign_key :visits, :pets, column: :pet_id, name: "fk_visits_pets"
  end
end
diagram.svg
ER diagram of the PetClinic schema drawn by SchemaDrawer: owners, pets, types, vets, specialties, vet_specialties and visits with their columns, primary keys and foreign keys

Every variant of the sample produces these seven tables. This diagram was drawn from the Flyway variant on PostgreSQL 18; on MySQL the types read INT and VARCHAR, on Oracle the names are upper case.

Run it

Draw your ActiveRecord (Rails) migrations

One multipart request queues the drawing; poll the job until it succeeds and download the SVG. Or let the GitHub Action do it and open a pull request with the diagram.

With curl

curl -X POST https://schemadrawer.com/api/v1/drawing \
  -H "Request-Id: $(uuidgen)" \
  -F "userId=5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f" \
  -F "migrationType=ACTIVE_RECORD" \
  -F "databaseType=POSTGRESQL" \
  -F "version=18" \
  -F "files=@db/migrate/001_create_owners_and_pets.rb" \
  -F "files=@db/migrate/002_create_vets.rb" \
  -F "files=@db/migrate/003_create_visits.rb"
# {"jobId":"0b6e2f4c-8d1a-4c3e-9f7a-2a5b6c7d8e9f"}

Then poll GET https://schemadrawer.com/api/v1/drawing/{jobId} until status is SUCCESS and fetch diagramUrl. Details in the getting started guide and the API reference.

With the GitHub Action

- uses: schemadrawercom/action@v1
  with:
    sql-directory: db/migrate
    output-path: docs/schema-diagram.svg
    migration-type: ACTIVE_RECORD
    database-type: POSTGRESQL
    database-version: '18'
    github-token: ${{ secrets.GITHUB_TOKEN }}

The action uploads the directory, waits for the diagram and opens a pull request with the SVG. See the action reference.

Good to know

  • A migration that needs the application, its models, its gems or Rails.env, cannot run.
  • schema_migrations and ar_internal_metadata are left out of the diagram.
  • A drawing may take up to 120 seconds; a job that waits in the queue longer than 10 minutes fails rather than draws. Uploads of up to 100 MB and 2000 files are accepted.
From the blog

Reading about ActiveRecord (Rails) and migrations

Draw your ActiveRecord (Rails) schema now

Upload the migration directory, get an SVG back. Free while we build it.