気ままに気ままのエンジニアブログ

定期的に得た知見を気ままに発信中

【heroku/Rails】「You might need to specify "USING opponent::integer"」エラー。カラムを変更するだけでは解決できなかった話

こんにちは。

もうすぐクリスマス。今年もウキウキしたいと思います。

どうもハチマキです。

はじめに

このエラーの解決方法はいくつかググるとヒットしましたが、それらでは解決できず、解決するのに結局数日を費やしました。。辛かった。。
同じ境地に立っている方々のソリューションになれば幸いです。

では早速行きましょう!

本日の概要 : You might need to specify "USING opponent::integer"の解決方法

事前情報

今回はこのようなテーブルを使っていきます(modelにenumを定義し、整数管理をしてます)

create_table "schedule_results", force: :cascade do |t|
    t.datetime "match_date_time"
    t.integer "section", null: false
    t.integer "opponent", null: false
    t.integer "match_result"
    t.integer "stadium", null: false
    t.integer "home_and_away", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

事象

herokuにデプロイするために、$ git push heroku masterを実行し、いざ!$ heroku run rails db:migrateを実行したら下記エラーが発生。

エラー例

$ heroku run rails db:migrate

Running rails db:migrate on ⬢ アプリ名... up, run.2812 (Free)
D, [2020-11-04T01:03:12.699380 #4] DEBUG -- :    (12.7ms)  CREATE TABLE "schema_migrations" ("version" character varying NOT NULL PRIMARY KEY)
D, [2020-11-04T01:03:12.710028 #4] DEBUG -- :    (7.1ms)  CREATE TABLE "ar_internal_metadata" ("key" character varying NOT NULL PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
D, [2020-11-04T01:03:12.712139 #4] DEBUG -- :    (0.9ms)  SELECT pg_try_advisory_lock(5119105135108451025)
D, [2020-11-04T01:03:12.729785 #4] DEBUG -- :    (1.1ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
I, [2020-11-04T01:03:12.731636 #4]  INFO -- : Migrating to CreateScheduleResults (20201026011945)
D, [2020-11-04T01:03:12.735697 #4] DEBUG -- :    (0.8ms)  BEGIN
== 20201026011945 CreateScheduleResults: migrating ============================
-- create_table(:schedule_results)
D, [2020-11-04T01:03:12.743729 #4] DEBUG -- :    (7.1ms)  CREATE TABLE "schedule_results" ("id" bigserial primary key, "match_date_time" timestamp, "section" integer, "opponent" character varying, "match_result" character varying, "stadium" character varying, "home_and_away" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
   -> 0.0079s
== 20201026011945 CreateScheduleResults: migrated (0.0080s) ===================

D, [2020-11-04T01:03:12.749135 #4] DEBUG -- :   ActiveRecord::SchemaMigration Create (0.9ms)  INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version"  [["version", "20201026011945"]]
D, [2020-11-04T01:03:12.751863 #4] DEBUG -- :    (2.4ms)  COMMIT
I, [2020-11-04T01:03:12.751984 #4]  INFO -- : Migrating to ChangeDatatypeOpponentOfScheduleResults (20201027022232)
D, [2020-11-04T01:03:12.753420 #4] DEBUG -- :    (0.7ms)  BEGIN
== 20201027022232 ChangeDatatypeOpponentOfScheduleResults: migrating ==========
-- change_column(:schedule_results, :opponent, :integer)
D, [2020-11-04T01:03:12.755207 #4] DEBUG -- :    (1.4ms)  ALTER TABLE "schedule_results" ALTER COLUMN "opponent" TYPE integer
D, [2020-11-04T01:03:12.756104 #4] DEBUG -- :    (0.7ms)  ROLLBACK
D, [2020-11-04T01:03:12.757154 #4] DEBUG -- :    (0.8ms)  SELECT pg_advisory_unlock(5119105135108451025)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DatatypeMismatch: ERROR:  column "opponent" cannot be cast automatically to type integer
HINT:  You might need to specify "USING opponent::integer".

エラー文を読んでいくと、
PG::DatatypeMismatch: ERROR: column "opponent" cannot be cast automatically to type integer
HINT: You might need to specify "USING opponent::integer".

つまり「opponentカラムを"USING opponent::integer"」に指定する必要があるとのことです。
なので、言われた通りマイグレーションファイルを作成しopponentカラムを"USING opponent::integer"に定義し直しました。

が、、、、、
変更後に再度$ git push heroku master、$ heroku run rails db:migrateを実行したら同じエラーが発生しました。。
このエラーを解決する記事は、どれもこれもエラーに出ているカラムを"USING opponent::integer"に変更すれば良い!という解決方法が多々ありましたが、それでは解決できませんでした。。

ここで数日こちらのエラー様と向き合い続けました。

原因の推測

なぜ"USING opponent::integer"を定義し直したのに同じエラーが発生するのか。。

・原因1:うまくカラムに"USING opponent::integer"が反映されていない?
・原因2:解決策がそもそも"USING opponent::integer"を定義することじゃない?
・原因3:SQLiteじゃ$ heroku run rails db:migrateできないの?
などなど、ググりながら推測してました。

原因はこれ!

結論!
すでに存在していたマイグレーションファイルが読み込まれ、本来integerで保存されるのに"opponent" character varyingになっていたことが原因でした。

よって、$ heroku run rails db:migrateを実行しても、新たに変更を加えたマイグレーションファイルではなかったため、$ heroku run rails db:migrateしてもherokuで作成されるDBに反映されてなかったということでした。

つまり"USING opponent::integer"にカラムを変更しなくてもデータ型をintegerにしていれば解決できるエラーでした。

$ heroku run rails db:migrate

・
・
・
== 20201026011945 CreateScheduleResults: migrating ============================
-- create_table(:schedule_results)
D, [2020-11-04T01:03:12.743729 #4] DEBUG -- :    (7.1ms)  CREATE TABLE "schedule_results" ("id" bigserial primary key, "match_date_time" timestamp, "section" integer, "opponent" character varying, ←ここ!!!
"match_result" character varying, "stadium" character varying, "home_and_away" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
   -> 0.0079s
== 20201026011945 CreateScheduleResults: migrated (0.0080s) =================== 
・
・
・

解決方法

私の対応としては、アプリケーションを作りたてだったこともあり、一度テーブルと既存のマイグレーションファイルを全て削除し、opponentカラムを等を"integer"に定義し直したテーブルを再度作成し、解決に至りました。

def change
    create_table :schedule_results do |t|
      t.datetime :match_date_time
      t.integer :section, null: false
      t.integer :opponent, null: false
      t.integer :match_result, default: ""
      t.integer :stadium, null: false
      t.integer :home_and_away, null: false

      t.timestamps

    end

再度$ git push heroku masterを実行し、一度$ heroku run rails db:resetでherokuの既存レコードを全て削除してから、

$ heroku run rails db:migrate

Running rails db:migrate on ⬢アプリ名... up, run.3410 (Free)

D, [2020-11-04T01:49:45.407343 #4] DEBUG -- :    (695.6ms)  CREATE TABLE "schema_migrations" ("version" character varying NOT NULL PRIMARY KEY)
D, [2020-11-04T01:49:45.505564 #4] DEBUG -- :    (95.2ms)  CREATE TABLE "ar_internal_metadata" ("key" character varying NOT NULL PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
D, [2020-11-04T01:49:45.507839 #4] DEBUG -- :    (0.9ms)  SELECT pg_try_advisory_lock(5119105135108451025)
D, [2020-11-04T01:49:45.761253 #4] DEBUG -- :    (1.0ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
I, [2020-11-04T01:49:45.762651 #4]  INFO -- : Migrating to CreateScheduleResults (20201104014024)
D, [2020-11-04T01:49:45.765550 #4] DEBUG -- :    (0.7ms)  BEGIN
== 20201104014024 CreateScheduleResults: migrating ============================
-- create_table(:schedule_results)
D, [2020-11-04T01:49:45.818313 #4] DEBUG -- :    (51.2ms)  CREATE TABLE "schedule_results" ("id" bigserial primary key, "match_date_time" timestamp, "section" integer NOT NULL, "opponent" integer NOT NULL, "match_result" integer DEFAULT NULL, "stadium" integer NOT NULL, "home_and_away" integer NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
   -> 0.0527s
== 20201104014024 CreateScheduleResults: migrated (0.0528s) ===================

D, [2020-11-04T01:49:45.822740 #4] DEBUG -- :   ActiveRecord::SchemaMigration Create (0.9ms)  INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version"  [["version", "20201104014024"]]
D, [2020-11-04T01:49:45.824364 #4] DEBUG -- :    (1.4ms)  COMMIT
D, [2020-11-04T01:49:45.831674 #4] DEBUG -- :   ActiveRecord::InternalMetadata Load (1.8ms)  SELECT  "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2  [["key", "environment"], ["LIMIT", 1]]
D, [2020-11-04T01:49:45.838134 #4] DEBUG -- :    (0.7ms)  BEGIN
D, [2020-11-04T01:49:45.840383 #4] DEBUG -- :   ActiveRecord::InternalMetadata Create (0.9ms)  INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "key"  [["key", "environment"], ["value", "production"], ["created_at", "2020-11-04 01:49:45.838415"], ["updated_at", "2020-11-04 01:49:45.838415"]]
D, [2020-11-04T01:49:45.842165 #4] DEBUG -- :    (1.6ms)  COMMIT
D, [2020-11-04T01:49:45.844081 #4] DEBUG -- :    (1.8ms)  SELECT pg_advisory_unlock(5119105135108451025)

ちゃんと新たに作成したマイグレーションファイルでDBcreateされました!やっと正常に動き出しました!!
ここまで長かったぁ。。。お疲れ様でした。