Skip to content

good_jobsテーブルに不足しているカラムを追加#9405

Merged
komagata merged 2 commits intomainfrom
fix/add-missing-good-jobs-columns
Dec 19, 2025
Merged

good_jobsテーブルに不足しているカラムを追加#9405
komagata merged 2 commits intomainfrom
fix/add-missing-good-jobs-columns

Conversation

@komagata
Copy link
Copy Markdown
Member

@komagata komagata commented Dec 19, 2025

Summary

  • 本番環境のgood_jobsテーブルが古いスキーマで作成されていたため、error_event等のカラムが存在せずエラーが発生
  • 不足している可能性のあるカラムとインデックスを条件付きで追加するマイグレーションを作成

エラー内容

Undeclared attribute type for enum 'error_event' in GoodJob::Job.
Enums must be backed by a database column or declared with an explicit type via `attribute`.

追加するカラム(存在しない場合のみ)

  • error_event (integer)
  • labels (text[])
  • locked_by_id (uuid)
  • locked_at (datetime)
  • is_discrete (boolean)
  • executions_count (integer)
  • job_class (text)
  • batch_id (uuid)
  • batch_callback_id (uuid)

動作確認

  • ローカル環境でマイグレーション実行確認(既存カラムはスキップ)
  • ロールバック・再実行の動作確認
  • テスト実行確認

関連PR

Test plan

  • CIが通ることを確認

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • ジョブ関連テーブルのデータベーススキーマを更新し、複数の列とインデックスを追加しました。
    • 検索・ロック・バッチ関連のパフォーマンス向上を目的としたインデックス最適化を実施しました。
    • スキーマバージョンを更新しました。

✏️ Tip: You can customize this high-level summary in your review settings.

本番環境のgood_jobsテーブルが古いスキーマで作成されていたため、
error_event等のカラムが存在せずエラーが発生していた。

不足している可能性のあるカラムとインデックスを条件付きで追加。
column_exists?/index_exists?でチェックするため、開発環境・本番環境
どちらでも安全に実行可能。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 19, 2025

Walkthrough

Rails 7.2マイグレーションを追加し、good_jobs テーブルへ存在しない場合に複数のカラムと関連インデックスを条件付きで追加します。スキーマバージョンも更新されます。(50語以内)

Changes

Cohort / File(s) 変更内容
GoodJobs マイグレーション
db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb
good_jobs テーブルへ条件付きでカラムを追加:error_event, labels, locked_by_id, locked_at, is_discrete, executions_count, job_class, batch_id, batch_callback_id。さらに、部分インデックスや条件付きインデックスを含む複数のインデックス(labels, locked_by_id, batch_id, batch_callback_id, job_class、および priority, scheduled_at の複合部分インデックス等)を条件付きで追加。
スキーマ更新
db/schema.rb
ActiveRecord スキーマバージョンを 2025_12_20_000001 に更新。good_jobsindex_good_jobs_on_job_class を追加。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • マイグレーション内の条件付き分岐(カラム/インデックス存在チェック)の網羅と副作用確認
  • インデックス定義(部分インデックス条件、複合インデックスの並び順)の正確さ確認
  • スキーマバージョン同期と既存デプロイ環境への影響評価

Possibly related PRs

Suggested reviewers

  • okuramasafumi

Poem

🐇 今日はカラム植えよう、土をほるように
新しい列が並び、インデックスが光る
スキーマの庭に一歩ずつ道をつけて
条件を確かめて、やさしく実行するよ
✨ ぴょんと祝おう、マイグレーションの朝 ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PRのタイトルは変更内容を正確に要約しており、good_jobsテーブルに不足しているカラムを追加することが明確に伝わっています。
Description check ✅ Passed PR説明はテンプレートの構造に部分的に従っており、概要・エラー内容・追加するカラム・動作確認などの重要な情報が含まれていますが、テンプレートの「Issue」セクションが欠落しています。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/add-missing-good-jobs-columns

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9353cd1 and fcc0e6d.

📒 Files selected for processing (1)
  • db/schema.rb (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
db/**

📄 CodeRabbit inference engine (AGENTS.md)

Database migrations and schema should be stored in db/ directory; app-specific utilities in lib/; static assets in public/

Files:

  • db/schema.rb
**/*.rb

📄 CodeRabbit inference engine (AGENTS.md)

Ruby code should use 2-space indentation, snake_case for method names, and CamelCase for class names, enforced by RuboCop (.rubocop.yml)

Files:

  • db/schema.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

  • まずFat Controllerを避け、次にFat Modelを避ける。
  • Serviceクラスの乱用を避ける。
  • controller concernを作ろうとしたらPORO(Plain Old Ruby Object)やActiveRecordモデルでの実装で代替できないか検討する。

Rails Patterns

  • ViewHelperにメソッドを実装する時にはまずDecoratorパターンを使うことを検討する。(active_decorator gemを導入しているのでそれを使う)
  • 複雑なActiveRecordクエリがあり、再利用できそうな場合はQueryObjectパターンを検討する。(rails-patterns gemを導入しているのでそれのQuery機能を使う)
  • Viewにpartialを作る場合はViewComponentを使うことを検討する。
  • 複数のActiveRecordモデルを操作する1つの責務がある時や外部APIとやりとりする処理がある場合にはInteractorオブジェクトパターンを検討する。(interactor gemを導入しているのでそれを使う)
  • 複数のInteractorを実行するような処理がある場合Organizerオブジェクトパターンを検討する。(interactor gemを導入しており、その中にOrganizerの機能があるので使う)

Files:

  • db/schema.rb
🧠 Learnings (2)
📓 Common learnings
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/models/graduation_notifier.rb:23-28
Timestamp: 2025-09-12T21:16:47.639Z
Learning: Rails upgrade PRにおいて、configuration systemの変更やwebhook設定の改善提案も、アップグレードに直接関連しない場合は別PRで対応すべきである。PRのスコープ維持が重要。
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:131-135
Timestamp: 2025-09-12T21:18:00.834Z
Learning: Rails アップグレードPRにおいて、product_review_not_completed メソッドの webhook URL 設定の shared フォールバック追加も、設定システム全体の変更として別PRで対応すべきである。
Learnt from: ryufuta
Repo: fjordllc/bootcamp PR: 9115
File: db/migrate/20250902024949_add_unique_index_to_correct_answers.rb:1-5
Timestamp: 2025-11-13T09:20:36.030Z
Learning: fjordllc/bootcamp プロジェクトでは、データの整合性を保つためのデータ修正には data-migrate gem を使用し、db/data/ ディレクトリ配下にデータマイグレーションファイルを作成する運用を採用している。スキーマ変更(db/migrate/)とデータ変更(db/data/)を分離することで、より安全で管理しやすい構成を実現している。
Learnt from: Miya096jp
Repo: fjordllc/bootcamp PR: 9102
File: db/migrate/20250831234516_remove_unique_index_from_buzzes_title.rb:1-5
Timestamp: 2025-09-04T01:50:47.773Z
Learning: fjordllc/bootcampプロジェクトでは、マイグレーションにおいてdisable_ddl_transaction!やalgorithm: :concurrentlyは使用せず、標準的なRailsのchangeメソッド内でremove_indexを実行する慣例がある。
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: db/migrate/20250828192202_add_missing_columns_to_good_jobs.rb:4-10
Timestamp: 2025-09-11T14:18:20.194Z
Learning: GoodJobやその他の外部gemが生成するマイグレーションファイルは、gem内部のロジックと密接に連携しているため、null制約やデフォルト値の追加などの変更を行うべきではない。gemのアップグレードパスに従い、生成されたマイグレーションをそのまま使用することが適切。
Learnt from: CR
Repo: fjordllc/bootcamp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-26T08:23:30.927Z
Learning: Pull requests should include clear description, linked issues, screenshots for UI changes, migration notes, and rollback plan if relevant
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:52-56
Timestamp: 2025-09-12T21:17:45.295Z
Learning: Rails upgrade PRにおいて、configuration systemの改善提案(shared configuration fallback等)も、アップグレードに直接関連しない場合は別PRで対応すべきである。PRのスコープ維持が重要。
Learnt from: thmz337
Repo: fjordllc/bootcamp PR: 8857
File: db/migrate/20250624141527_remove_experience_from_users.rb:6-8
Timestamp: 2025-06-27T14:06:44.472Z
Learning: Railsのマイグレーションのdownメソッドでは、元のスキーマの正確な定義を確認してから制約を追加する必要がある。元のカラムに制約がない場合、ロールバック時に制約を追加すると元の状態と異なってしまう。
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: db/migrate/20250830033535_add_default_to_pair_works_wip.rb:1-5
Timestamp: 2025-08-31T03:17:44.812Z
Learning: 新機能のマイグレーションで、まだ本番環境にリリースされていない場合は、既存レコードのバックフィル処理は不要。開発環境でrails db:resetが可能な状況では特に、デフォルト値の変更のみで十分。
📚 Learning: 2025-09-08T04:55:46.649Z
Learnt from: sharoa119
Repo: fjordllc/bootcamp PR: 8711
File: db/schema.rb:0-0
Timestamp: 2025-09-08T04:55:46.649Z
Learning: In this PR, the removal of length limits from companies.name and companies.website columns in db/schema.rb was unintentional - it was a case of accidentally lost constraints that needed to be restored to their original limits, not a deliberate design change.

Applied to files:

  • db/schema.rb
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (2)
db/schema.rb (2)

13-13: スキーマバージョンの更新が適切です。

新しいマイグレーション(20251220000001_add_missing_columns_to_good_jobs.rb)を反映したスキーマバージョンの更新が正しく行われています。


433-433: job_classカラムへのインデックス追加が適切です。

job_classカラムにインデックスが追加されており、ジョブクラスでのフィルタリングやソート処理のパフォーマンスが向上します。GoodJob gem (v4.12.1) の要件に沿った適切な変更です。


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb (1)

17-40: インデックス名の指定方法に軽微な不統一があります。

インデックス名の指定で、シンボル(:index_good_jobs_on_labels)と文字列("index_good_jobs_on_locked_by_id")が混在しています。統一性のため、すべてシンボルまたはすべて文字列に揃えることを推奨します。

🔎 統一化の提案
    unless index_exists?(:good_jobs, :locked_by_id, name: 'index_good_jobs_on_locked_by_id')
-     add_index :good_jobs, :locked_by_id, where: "locked_by_id IS NOT NULL", name: "index_good_jobs_on_locked_by_id"
+     add_index :good_jobs, :locked_by_id, where: "locked_by_id IS NOT NULL", name: :index_good_jobs_on_locked_by_id
    end

    unless index_exists?(:good_jobs, :batch_id, name: 'index_good_jobs_on_batch_id')
-     add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL", name: 'index_good_jobs_on_batch_id'
+     add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL", name: :index_good_jobs_on_batch_id
    end

    unless index_exists?(:good_jobs, :batch_callback_id, name: 'index_good_jobs_on_batch_callback_id')
-     add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL", name: 'index_good_jobs_on_batch_callback_id'
+     add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL", name: :index_good_jobs_on_batch_callback_id
    end
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f72e11 and 9353cd1.

📒 Files selected for processing (1)
  • db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
db/**

📄 CodeRabbit inference engine (AGENTS.md)

Database migrations and schema should be stored in db/ directory; app-specific utilities in lib/; static assets in public/

Files:

  • db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb
**/*.rb

📄 CodeRabbit inference engine (AGENTS.md)

Ruby code should use 2-space indentation, snake_case for method names, and CamelCase for class names, enforced by RuboCop (.rubocop.yml)

Files:

  • db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

  • まずFat Controllerを避け、次にFat Modelを避ける。
  • Serviceクラスの乱用を避ける。
  • controller concernを作ろうとしたらPORO(Plain Old Ruby Object)やActiveRecordモデルでの実装で代替できないか検討する。

Rails Patterns

  • ViewHelperにメソッドを実装する時にはまずDecoratorパターンを使うことを検討する。(active_decorator gemを導入しているのでそれを使う)
  • 複雑なActiveRecordクエリがあり、再利用できそうな場合はQueryObjectパターンを検討する。(rails-patterns gemを導入しているのでそれのQuery機能を使う)
  • Viewにpartialを作る場合はViewComponentを使うことを検討する。
  • 複数のActiveRecordモデルを操作する1つの責務がある時や外部APIとやりとりする処理がある場合にはInteractorオブジェクトパターンを検討する。(interactor gemを導入しているのでそれを使う)
  • 複数のInteractorを実行するような処理がある場合Organizerオブジェクトパターンを検討する。(interactor gemを導入しており、その中にOrganizerの機能があるので使う)

Files:

  • db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb
🧠 Learnings (2)
📓 Common learnings
Learnt from: sharoa119
Repo: fjordllc/bootcamp PR: 8711
File: db/schema.rb:0-0
Timestamp: 2025-09-08T04:55:46.649Z
Learning: In this PR, the removal of length limits from companies.name and companies.website columns in db/schema.rb was unintentional - it was a case of accidentally lost constraints that needed to be restored to their original limits, not a deliberate design change.
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: db/migrate/20250828192202_add_missing_columns_to_good_jobs.rb:4-10
Timestamp: 2025-09-11T14:18:20.194Z
Learning: GoodJobやその他の外部gemが生成するマイグレーションファイルは、gem内部のロジックと密接に連携しているため、null制約やデフォルト値の追加などの変更を行うべきではない。gemのアップグレードパスに従い、生成されたマイグレーションをそのまま使用することが適切。
Learnt from: thmz337
Repo: fjordllc/bootcamp PR: 8857
File: db/migrate/20250624141527_remove_experience_from_users.rb:6-8
Timestamp: 2025-06-27T14:06:44.472Z
Learning: Railsのマイグレーションのdownメソッドでは、元のスキーマの正確な定義を確認してから制約を追加する必要がある。元のカラムに制約がない場合、ロールバック時に制約を追加すると元の状態と異なってしまう。
Learnt from: Miya096jp
Repo: fjordllc/bootcamp PR: 9102
File: db/migrate/20250831234516_remove_unique_index_from_buzzes_title.rb:1-5
Timestamp: 2025-09-04T01:50:47.773Z
Learning: fjordllc/bootcampプロジェクトでは、マイグレーションにおいてdisable_ddl_transaction!やalgorithm: :concurrentlyは使用せず、標準的なRailsのchangeメソッド内でremove_indexを実行する慣例がある。
Learnt from: ryufuta
Repo: fjordllc/bootcamp PR: 9115
File: db/migrate/20250902024949_add_unique_index_to_correct_answers.rb:1-5
Timestamp: 2025-11-13T09:20:36.030Z
Learning: fjordllc/bootcamp プロジェクトでは、データの整合性を保つためのデータ修正には data-migrate gem を使用し、db/data/ ディレクトリ配下にデータマイグレーションファイルを作成する運用を採用している。スキーマ変更(db/migrate/)とデータ変更(db/data/)を分離することで、より安全で管理しやすい構成を実現している。
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: db/migrate/20250830033535_add_default_to_pair_works_wip.rb:1-5
Timestamp: 2025-08-31T03:17:44.812Z
Learning: 新機能のマイグレーションで、まだ本番環境にリリースされていない場合は、既存レコードのバックフィル処理は不要。開発環境でrails db:resetが可能な状況では特に、デフォルト値の変更のみで十分。
📚 Learning: 2025-09-11T14:18:20.194Z
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: db/migrate/20250828192202_add_missing_columns_to_good_jobs.rb:4-10
Timestamp: 2025-09-11T14:18:20.194Z
Learning: GoodJobやその他の外部gemが生成するマイグレーションファイルは、gem内部のロジックと密接に連携しているため、null制約やデフォルト値の追加などの変更を行うべきではない。gemのアップグレードパスに従い、生成されたマイグレーションをそのまま使用することが適切。

Applied to files:

  • db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test

Comment on lines +4 to +41
def change
# Add missing columns to good_jobs table if they don't exist
add_column :good_jobs, :error_event, :integer, limit: 2 unless column_exists?(:good_jobs, :error_event)
add_column :good_jobs, :labels, :text, array: true unless column_exists?(:good_jobs, :labels)
add_column :good_jobs, :locked_by_id, :uuid unless column_exists?(:good_jobs, :locked_by_id)
add_column :good_jobs, :locked_at, :datetime unless column_exists?(:good_jobs, :locked_at)
add_column :good_jobs, :is_discrete, :boolean unless column_exists?(:good_jobs, :is_discrete)
add_column :good_jobs, :executions_count, :integer unless column_exists?(:good_jobs, :executions_count)
add_column :good_jobs, :job_class, :text unless column_exists?(:good_jobs, :job_class)
add_column :good_jobs, :batch_id, :uuid unless column_exists?(:good_jobs, :batch_id)
add_column :good_jobs, :batch_callback_id, :uuid unless column_exists?(:good_jobs, :batch_callback_id)

# Add missing indexes
unless index_exists?(:good_jobs, :labels, name: 'index_good_jobs_on_labels')
add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)", name: :index_good_jobs_on_labels
end

unless index_exists?(:good_jobs, :locked_by_id, name: 'index_good_jobs_on_locked_by_id')
add_index :good_jobs, :locked_by_id, where: "locked_by_id IS NOT NULL", name: "index_good_jobs_on_locked_by_id"
end

unless index_exists?(:good_jobs, :batch_id, name: 'index_good_jobs_on_batch_id')
add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL", name: 'index_good_jobs_on_batch_id'
end

unless index_exists?(:good_jobs, :batch_callback_id, name: 'index_good_jobs_on_batch_callback_id')
add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL", name: 'index_good_jobs_on_batch_callback_id'
end

unless index_exists?(:good_jobs, :job_class, name: 'index_good_jobs_on_job_class')
add_index :good_jobs, :job_class, name: :index_good_jobs_on_job_class
end

unless index_exists?(:good_jobs, [:priority, :scheduled_at], name: 'index_good_jobs_on_priority_scheduled_at_unfinished_unlocked')
add_index :good_jobs, [:priority, :scheduled_at], order: { priority: "ASC NULLS LAST", scheduled_at: :asc },
where: "finished_at IS NULL AND locked_by_id IS NULL", name: :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked
end
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

ロールバック時の動作に注意が必要です。

インライン条件(unless column_exists?)を使用しているため、マイグレーション実行時には存在しないカラム・インデックスのみが追加されますが、ロールバック時はRailsがすべてのカラム・インデックスの削除を試みます。これは、このマイグレーション以前から既に存在していたカラム・インデックスも削除してしまう可能性があります。

本番環境でのスキーマずれを修正する目的であれば、より安全な実装としてreversibleブロックの使用を検討してください。

🔎 推奨される実装例
  def change
-   # Add missing columns to good_jobs table if they don't exist
-   add_column :good_jobs, :error_event, :integer, limit: 2 unless column_exists?(:good_jobs, :error_event)
-   add_column :good_jobs, :labels, :text, array: true unless column_exists?(:good_jobs, :labels)
-   add_column :good_jobs, :locked_by_id, :uuid unless column_exists?(:good_jobs, :locked_by_id)
-   add_column :good_jobs, :locked_at, :datetime unless column_exists?(:good_jobs, :locked_at)
-   add_column :good_jobs, :is_discrete, :boolean unless column_exists?(:good_jobs, :is_discrete)
-   add_column :good_jobs, :executions_count, :integer unless column_exists?(:good_jobs, :executions_count)
-   add_column :good_jobs, :job_class, :text unless column_exists?(:good_jobs, :job_class)
-   add_column :good_jobs, :batch_id, :uuid unless column_exists?(:good_jobs, :batch_id)
-   add_column :good_jobs, :batch_callback_id, :uuid unless column_exists?(:good_jobs, :batch_callback_id)
-
-   # Add missing indexes
-   unless index_exists?(:good_jobs, :labels, name: 'index_good_jobs_on_labels')
-     add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)", name: :index_good_jobs_on_labels
-   end
-
-   unless index_exists?(:good_jobs, :locked_by_id, name: 'index_good_jobs_on_locked_by_id')
-     add_index :good_jobs, :locked_by_id, where: "locked_by_id IS NOT NULL", name: "index_good_jobs_on_locked_by_id"
-   end
-
-   unless index_exists?(:good_jobs, :batch_id, name: 'index_good_jobs_on_batch_id')
-     add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL", name: 'index_good_jobs_on_batch_id'
-   end
-
-   unless index_exists?(:good_jobs, :batch_callback_id, name: 'index_good_jobs_on_batch_callback_id')
-     add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL", name: 'index_good_jobs_on_batch_callback_id'
-   end
-
-   unless index_exists?(:good_jobs, :job_class, name: 'index_good_jobs_on_job_class')
-     add_index :good_jobs, :job_class, name: :index_good_jobs_on_job_class
-   end
-
-   unless index_exists?(:good_jobs, [:priority, :scheduled_at], name: 'index_good_jobs_on_priority_scheduled_at_unfinished_unlocked')
-     add_index :good_jobs, [:priority, :scheduled_at], order: { priority: "ASC NULLS LAST", scheduled_at: :asc },
-       where: "finished_at IS NULL AND locked_by_id IS NULL", name: :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked
-   end
+   reversible do |dir|
+     dir.up do
+       # Add missing columns to good_jobs table if they don't exist
+       add_column :good_jobs, :error_event, :integer, limit: 2 unless column_exists?(:good_jobs, :error_event)
+       add_column :good_jobs, :labels, :text, array: true unless column_exists?(:good_jobs, :labels)
+       add_column :good_jobs, :locked_by_id, :uuid unless column_exists?(:good_jobs, :locked_by_id)
+       add_column :good_jobs, :locked_at, :datetime unless column_exists?(:good_jobs, :locked_at)
+       add_column :good_jobs, :is_discrete, :boolean unless column_exists?(:good_jobs, :is_discrete)
+       add_column :good_jobs, :executions_count, :integer unless column_exists?(:good_jobs, :executions_count)
+       add_column :good_jobs, :job_class, :text unless column_exists?(:good_jobs, :job_class)
+       add_column :good_jobs, :batch_id, :uuid unless column_exists?(:good_jobs, :batch_id)
+       add_column :good_jobs, :batch_callback_id, :uuid unless column_exists?(:good_jobs, :batch_callback_id)
+
+       # Add missing indexes
+       unless index_exists?(:good_jobs, :labels, name: 'index_good_jobs_on_labels')
+         add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)", name: :index_good_jobs_on_labels
+       end
+
+       unless index_exists?(:good_jobs, :locked_by_id, name: 'index_good_jobs_on_locked_by_id')
+         add_index :good_jobs, :locked_by_id, where: "locked_by_id IS NOT NULL", name: "index_good_jobs_on_locked_by_id"
+       end
+
+       unless index_exists?(:good_jobs, :batch_id, name: 'index_good_jobs_on_batch_id')
+         add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL", name: 'index_good_jobs_on_batch_id'
+       end
+
+       unless index_exists?(:good_jobs, :batch_callback_id, name: 'index_good_jobs_on_batch_callback_id')
+         add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL", name: 'index_good_jobs_on_batch_callback_id'
+       end
+
+       unless index_exists?(:good_jobs, :job_class, name: 'index_good_jobs_on_job_class')
+         add_index :good_jobs, :job_class, name: :index_good_jobs_on_job_class
+       end
+
+       unless index_exists?(:good_jobs, [:priority, :scheduled_at], name: 'index_good_jobs_on_priority_scheduled_at_unfinished_unlocked')
+         add_index :good_jobs, [:priority, :scheduled_at], order: { priority: "ASC NULLS LAST", scheduled_at: :asc },
+           where: "finished_at IS NULL AND locked_by_id IS NULL", name: :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked
+       end
+     end
+
+     dir.down do
+       # Remove only if columns were added by this migration
+       remove_column :good_jobs, :error_event if column_exists?(:good_jobs, :error_event)
+       remove_column :good_jobs, :labels if column_exists?(:good_jobs, :labels)
+       remove_column :good_jobs, :locked_by_id if column_exists?(:good_jobs, :locked_by_id)
+       remove_column :good_jobs, :locked_at if column_exists?(:good_jobs, :locked_at)
+       remove_column :good_jobs, :is_discrete if column_exists?(:good_jobs, :is_discrete)
+       remove_column :good_jobs, :executions_count if column_exists?(:good_jobs, :executions_count)
+       remove_column :good_jobs, :job_class if column_exists?(:good_jobs, :job_class)
+       remove_column :good_jobs, :batch_id if column_exists?(:good_jobs, :batch_id)
+       remove_column :good_jobs, :batch_callback_id if column_exists?(:good_jobs, :batch_callback_id)
+
+       # Remove indexes
+       remove_index :good_jobs, name: 'index_good_jobs_on_labels' if index_exists?(:good_jobs, :labels, name: 'index_good_jobs_on_labels')
+       remove_index :good_jobs, name: 'index_good_jobs_on_locked_by_id' if index_exists?(:good_jobs, :locked_by_id, name: 'index_good_jobs_on_locked_by_id')
+       remove_index :good_jobs, name: 'index_good_jobs_on_batch_id' if index_exists?(:good_jobs, :batch_id, name: 'index_good_jobs_on_batch_id')
+       remove_index :good_jobs, name: 'index_good_jobs_on_batch_callback_id' if index_exists?(:good_jobs, :batch_callback_id, name: 'index_good_jobs_on_batch_callback_id')
+       remove_index :good_jobs, name: 'index_good_jobs_on_job_class' if index_exists?(:good_jobs, :job_class, name: 'index_good_jobs_on_job_class')
+       remove_index :good_jobs, name: 'index_good_jobs_on_priority_scheduled_at_unfinished_unlocked' if index_exists?(:good_jobs, [:priority, :scheduled_at], name: 'index_good_jobs_on_priority_scheduled_at_unfinished_unlocked')
+     end
+   end
  end

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +6 to +14
add_column :good_jobs, :error_event, :integer, limit: 2 unless column_exists?(:good_jobs, :error_event)
add_column :good_jobs, :labels, :text, array: true unless column_exists?(:good_jobs, :labels)
add_column :good_jobs, :locked_by_id, :uuid unless column_exists?(:good_jobs, :locked_by_id)
add_column :good_jobs, :locked_at, :datetime unless column_exists?(:good_jobs, :locked_at)
add_column :good_jobs, :is_discrete, :boolean unless column_exists?(:good_jobs, :is_discrete)
add_column :good_jobs, :executions_count, :integer unless column_exists?(:good_jobs, :executions_count)
add_column :good_jobs, :job_class, :text unless column_exists?(:good_jobs, :job_class)
add_column :good_jobs, :batch_id, :uuid unless column_exists?(:good_jobs, :batch_id)
add_column :good_jobs, :batch_callback_id, :uuid unless column_exists?(:good_jobs, :batch_callback_id)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the migration file exists and examine its contents
find . -name "*add_missing_columns_to_good_jobs*" -type f 2>/dev/null | head -5

# Also check for any GoodJob-related migrations in the codebase
find db/migrate -name "*good_job*" -type f 2>/dev/null | sort

Repository: fjordllc/bootcamp

Length of output: 232


🏁 Script executed:

#!/bin/bash
# Read the migration files to examine their content
echo "=== Create GoodJobs Migration ==="
head -50 ./db/migrate/20250828192201_create_good_jobs.rb

echo -e "\n=== Add Missing Columns Migration ==="
cat ./db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb

# Check Gemfile for GoodJob version
echo -e "\n=== GoodJob Gemfile Entry ==="
grep -i "good_job" Gemfile || echo "No good_job found in Gemfile"

Repository: fjordllc/bootcamp

Length of output: 4073


AddMissingColumnsToGoodJobs マイグレーションは削除してください。

CreateGoodJobs マイグレーション(20250828192201)にすべてのカラム(error_event、labels、locked_by_id、locked_at、is_discrete、executions_count、job_class、batch_id、batch_callback_id)が既に定義されています。AddMissingColumnsToGoodJobs マイグレーション(20251220000001)で同じカラムを条件付きで追加しようとしていますが、これは完全に冗長です。マイグレーションが順序通りに実行される場合、column_exists? チェックはすべて真になり、実際には何も実行されません。

不要なマイグレーション定義を削除し、CreateGoodJobs のみを保持してください。

🤖 Prompt for AI Agents
In db/migrate/20251220000001_add_missing_columns_to_good_jobs.rb around lines 6
to 14, remove the entire AddMissingColumnsToGoodJobs migration file (it
duplicates columns already defined in CreateGoodJobs); delete the file from the
repository (git rm) and commit the deletion, then run the usual migration sanity
steps (e.g., ensure schema/migration status is correct and run any necessary
migrations locally or on CI) so the codebase no longer contains the redundant
migration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant