ここでの問題は、Heroku のデフォルト設定である、アプリがプロダクション モードの場合 (つまり、ENV['RAILS_ENV']
またはENV['RACK_ENV']
=の場合) にのみ発生する微妙な問題です。production
Rails アプリがproduction
モードの場合、リクエストごとにクラス定義をリロードしません (development
ローカルで実行しているモードの場合とは異なります)。モデルのクラス定義の一部は、クラスのロード時にデータベース列からフェッチされる属性です。したがって、でクラスをロードしてproduction
からデータベースを変更すると、ロードされたクラスはデータベースが変更されたことを認識せずNoMethodError
、新しい列の を取得します。
Heroku のケースでこれがどのように発生したかを理解するには、次のシーケンスを検討してください。
Topic.find_all_by_featured
新しい列参照を
使用してデプロイされたアプリ
- アプリは Heroku によって自動的に再起動されます
- データベースの現在の状態 (
featured
列なし)からクラスをメモリにロードする要求がアプリに送信されます。
- あなたが実行します
heroku run bundle exec rake db:migrate
- Heroku のデータベースは新しい
featured
列で更新されます
- Heroku dyno のメモリに既にあるモデル クラスは再読み込みされません。彼らはまだ新しいコラムについて知りません。
- アプリをヒットしました。コードで参照されているフィールドがデータベース列のリスト (ステップ 1 でロードされたもの) にないため、Rails はエラーをスローします。
このような状況を回避するための正しい手順は、デプロイとデータベースの移行の両方でメンテナンス モードをオンにすることです。
$ heroku maintenance:on
$ git push heroku master
$ heroku run bundle exec rake db:migrate
$ heroku maintenance:off
デプロイおよび移行中にメンテナンスをオンにすると、アプリによって要求が処理されず、(列リストが正しくない) クラスが読み込まれないことが保証されます。データベースが適切な状態になった後にのみ、リクエストを許可します。