🚀

Rails標準migrationからridgepoleへの移行で開発体験を向上させる

に公開

はじめに

Rails アプリケーションのデータベーススキーマ管理において、標準のmigrationファイルからridgepoleによる宣言的スキーマ管理に移行した取り組みについて紹介します。

ridgepoleは、宣言的なスキーマ定義ファイル(Schemafile)を使用してデータベーススキーマを管理するgemです。今回の移行により、スキーマの可読性向上、環境間同期の簡素化、レビューしやすい差分管理を実現できました。

移行の背景と動機

Rails標準migrationの課題

従来のRails標準migrationには以下のような課題がありました:

  • 履歴管理の複雑さ: migrationファイルが時系列順に積み重なり、スキーマの全体像を把握しにくい
  • 環境間の差分: 開発・テスト・本番環境でmigrationの実行状況が異なる場合がある
  • レビューの困難さ: スキーマ変更の影響範囲を把握するのに時間がかかる
  • ロールバックの制約: 複雑なmigrationのロールバックが困難

ridgepoleのメリット

ridgepoleを導入することで、以下のメリットが期待できます:

  • 📋 宣言的な定義: 現在のスキーマ状態を一つのファイルで管理
  • 🔄 環境同期の簡素化: 環境間でのスキーマ同期が容易
  • 👀 レビューしやすい差分: スキーマ変更が分かりやすい
  • 🚀 確実なデプロイ: 宣言的な適用により予期しない状態を回避

実装内容

1. Gemfileへの追加

# Gemfile
gem 'ridgepole', '~> 3.0.4'

ridgepole v3.0.4を追加しました。このバージョンは安定性とRails 7.xとの互換性に優れています。

2. Schemafileの作成

既存のPostgreSQLスキーマをSchemafileに移行しました。主要なテーブルは以下の通りです:

# Schemafile
create_table "maintenance_tasks_runs", force: :cascade do |t|
  t.string "task_name", null: false
  t.datetime "started_at", precision: nil
  t.datetime "ended_at", precision: nil
  t.float "time_running", default: 0.0, null: false
  t.bigint "tick_count", default: 0, null: false
  # ... その他のカラム定義
  t.index ["task_name", "status", "created_at"], name: "index_maintenance_tasks_runs"
end

Schemafileには以下のテーブル群を定義しています:

  • Solid Queue関連テーブル: Rails 7.1で導入された新しいジョブキューシステム
  • Maintenance Tasks: 定期実行タスク管理テーブル

3. CI/CD環境の対応

GitHub Actions CI

.github/workflows/ci.ymlの変更点:

# テストデータベースのセットアップにridgepoleを追加
- name: Set up test database
  run: |
    bundle exec rails db:create db:migrate
    bundle exec ridgepole -c config/database.yml -E test --apply -f Schemafile
  env:
    RAILS_ENV: test
    MONGODB_URI: mongodb://root:password@127.0.0.1:27017/m4g3_test?authSource=admin
    DATABASE_URL: postgres://postgres:password@127.0.0.1:5432/m4g3_test
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: password

重要なポイントは、PostgreSQL認証のための環境変数(POSTGRES_USERPOSTGRES_PASSWORD)を追加したことです。

Render.com デプロイ設定

render.yamlの変更点:

# preDeployCommandをridgepoleに変更
preDeployCommand: bundle exec ridgepole -c config/database.yml --apply -f Schemafile

従来のrails db:prepare && rails db:migrateから、ridgepoleによるスキーマ適用に変更しました。

4. データベース設定の調整

config/database.ymlにPostgreSQL接続設定を追加:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: localhost
  port: 5432

test:
  <<: *default
  database: m4g3_test
  username: <%= ENV.fetch("POSTGRES_USER", "postgres") %>
  password: <%= ENV.fetch("POSTGRES_PASSWORD", "") %>

5. RuboCop設定の更新

.rubocop.ymlにSchemafileの除外設定を追加:

# Exclude Ridgepole Schemafile from RuboCop
AllCops:
  Exclude:
    - 'Schemafile'

Schemafileは機械生成されるファイルのため、RuboCopの対象から除外しています。

実装時の注意点とハマりポイント

1. PostgreSQL認証エラー

GitHub Actions CI環境で初期実装時に以下のエラーが発生:

FATAL: password authentication failed for user "postgres"

解決策: database.ymlと環境変数の設定を調整

# 環境変数を適切に参照
username: <%= ENV.fetch("POSTGRES_USER", "postgres") %>
password: <%= ENV.fetch("POSTGRES_PASSWORD", "") %>

2. ridgepoleコマンドの実行タイミング

最初はrails db:create db:migrateの後にridgepoleを実行していましたが、これにより二重管理の状態になってしまいました。

改善: migrationは最小限にとどめ、スキーマ管理はridgepoleに統一

3. 環境変数の統一

CI環境と本番環境で環境変数名を統一し、設定の一貫性を保つことが重要でした。

移行の効果とメリット

1. 開発体験の向上

  • スキーマの全体像が把握しやすい: 一つのファイルでスキーマ全体を確認可能
  • レビューが効率的: Pull Requestでスキーマ変更の影響範囲が明確
  • 環境間の差分解消: 宣言的な定義により環境間のスキーマ差分を回避

2. デプロイの安全性向上

  • 冪等性の確保: 何度実行しても同じ結果になる
  • ロールバック不要: 宣言的な定義により、desired stateへの収束

3. チーム開発の効率化

  • コンフリクトの減少: Schemafileでのマージコンフリクトは発見・解決が容易
  • ドキュメント性の向上: 現在のスキーマ状態が一目で理解可能

まとめ

Rails標準migrationからridgepoleへの移行により、以下の改善を実現できました:

  • 宣言的なスキーマ管理による可読性とメンテナンス性の向上
  • CI/CD統合による自動化とデプロイの安全性確保
  • チーム開発効率の向上とレビュープロセスの改善

ridgepoleは特に複雑なスキーマを持つアプリケーションや、チーム開発でスキーマ変更が頻繁に発生するプロジェクトにおいて威力を発揮します。

移行作業自体は段階的に進めることができるため、既存のRailsアプリケーションでも安全に導入できるのが大きなメリットです。データベーススキーマ管理に課題を感じている方は、ぜひridgepoleの導入を検討してみてください。

参考リンク

Discussion