GHワークフロー中のテストにおける奇妙な移行エラー

トピックテーブルとの外部キーリレーションシップを作成しようとしています。

奇妙な理由で、GitHubワークフローのテスト環境でテスト中に失敗しています。これは、数年前にコアマイグレーションで削除された、もはや存在しない親テーブルのフィールドにアクセスしようとしています!

エラーは PG::UndefinedColumn: ERROR: column topics.off_topic_count does not exist です。

ええ、2018年のコアマイグレーションで削除されたからです

テストプロセス中にこれが既に実行されたことを確認しました。

== 20180917024729 RemoveSuperfluousColumns: migrating =========================
== 20180917024729 RemoveSuperfluousColumns: migrated (0.0410s) ===============

古い親テーブルフィールドを明示的に参照しているわけではありません… SQL自体が生成されているように見えますが、現在の定義には不適切です。

== 20231119010101 CreateLocationsTopicTable: migrating ========================rake aborted!

[12035](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12036)StandardError: An error has occurred, this and all later migrations canceled: (StandardError)

[12036](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12037)

[12037](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12038)PG::UndefinedColumn: ERROR: column topics.off_topic_count does not exist

[12038](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12039)LINE 1: ...cs"."deleted_at", "topics"."highest_post_number", "topics"...

テーブル定義は非常にシンプルです。

class CreateLocationsTopicTable < ActiveRecord::Migration[7.0]
  def change
    create_table :locations_topic do |t|
      t.references :topic, foreign_key: true
      t.float :latitude, null: false

SNIP

さらに奇妙なのは、このマイグレーションが本番環境では機能することです!

何か洞察があれば大歓迎です!

「いいね!」 1

Oh、私はこのために良い古いRUBOCOPPEDになりました :policeman: :police_car:

Offenses:

db/migrate/20231119010101_create_locations_topic_table.rb:6:7: C: Discourse/NoAddReferenceOrAliasesActiveRecordMigration: ARメソッドのadd_reference、add_belongs_to、t.references、t.belongs_toは、
大きなテーブルではリスクが高く、バックグラウンドでのマジック操作が多すぎます。
代わりに、disable_ddl_transactions!マイグレーションを記述し、カスタムSQLを記述して
新しい列とCREATE INDEX CONCURRENTLYを追加してください。マイグレーションが途中で失敗した場合に再実行可能にするために、IF NOT EXISTS句を使用してください。

      t.references :topic, foreign_key: true
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

さて、それは問題の一部かもしれません。

マジック :magic_wand: が多すぎるのが問題です!

生きて学んでいくものです! :mortar_board:

「いいね!」 1

RuboCop のアドバイスは良いですが、このエラーの原因ではないと思います。(言及されている「リスク」とは、高トラフィックのテーブルのロックであり、本番環境のトラフィックに影響を与えるものです。テスト環境でエラーを引き起こすようなものではありません。)

おそらく、RAILS_ENV=test bin/rake db:drop db:create db:migrate (つまり、locations プラグインを有効にして、データベースを完全にゼロからマイグレーションする)を実行することで、ローカルでも同じエラーを再現できるはずです。

問題は、マイグレーション内で Rake タスクを呼び出している ことだと疑っています。コアでは、奇妙な副作用が発生する可能性があるため、マイグレーションで何らかのアプリケーションコードを実行することは一般的に避けています。生の SQL を使用するのが最善です。

この場合、ActiveRecord のスキーマキャッシュがマイグレーションの早い段階で(topics.off_topic_count がまだ存在する時に)読み込まれると想定しています。その後、Rake タスクが実行されると、古いスキーマキャッシュで実行されるため、ActiveRecord は存在しないカラムをロードしようとします。

Rake タスクを呼び出す前に ActiveRecord::Base.clear_cache! を追加することで軽減できるかもしれませんが、それは推奨ではありません :wink:。最善の方法は、Rake タスクの呼び出しを完全に避けることです。データベース内の何かを操作する必要がある場合は、マイグレーション内で生の SQL を使用してください。

「いいね!」 2

Davidさん、ありがとうございます。SQLステートメントに移行して、問題が解決するかどうか確認します…

これで解決しました、Davidさんありがとう!

「いいね!」 2

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.