1

コントローラーに次のメソッドがあります。

@featured_topics = Topic.find_all_by_featured(true)

ローカルでは問題なく動作しますが、サイトを Heroku にアップロードすると失敗し、NoMethodError が発生します。「おすすめ」は新しいコラムですが、必要なファイルをアップロードして、Heroku で rake db:migrate を実行しました。なぜ Heroku で動作しないのですか? サイトの残りの部分は引き続き機能します。

4

1 に答える 1

4

ここでの問題は、Heroku のデフォルト設定である、アプリがプロダクション モードの場合 (つまり、ENV['RAILS_ENV']またはENV['RACK_ENV']=の場合) にのみ発生する微妙な問題です。production

Rails アプリがproductionモードの場合、リクエストごとにクラス定義をリロードしません (developmentローカルで実行しているモードの場合とは異なります)。モデルのクラス定義の一部は、クラスのロード時にデータベース列からフェッチされる属性です。したがって、でクラスをロードしてproductionからデータベースを変更すると、ロードされたクラスはデータベースが変更されたことを認識せずNoMethodError、新しい列の を取得します。

Heroku のケースでこれがどのように発生したかを理解するには、次のシーケンスを検討してください。

  1. Topic.find_all_by_featured新しい列参照を 使用してデプロイされたアプリ
    1. アプリは Heroku によって自動的に再起動されます
    2. データベースの現在の状態 (featured列なし)からクラスをメモリにロードする要求がアプリに送信されます。
  2. あなたが実行しますheroku run bundle exec rake db:migrate
    1. Heroku のデータベースは新しいfeatured列で更新されます
    2. Heroku dyno のメモリに既にあるモデル クラスは再読み込みされません。彼らはまだ新しいコラムについて知りません。
  3. アプリをヒットしました。コードで参照されているフィールドがデータベース列のリスト (ステップ 1 でロードされたもの) にないため、Rails はエラーをスローします。

このような状況を回避するための正しい手順は、デプロイとデータベースの移行の両方でメンテナンス モードをオンにすることです。

$ heroku maintenance:on
$ git push heroku master
$ heroku run bundle exec rake db:migrate
$ heroku maintenance:off

デプロイおよび移行中にメンテナンスをオンにすると、アプリによって要求が処理されず、(列リストが正しくない) クラスが読み込まれないことが保証されます。データベースが適切な状態になった後にのみ、リクエストを許可します。

于 2013-03-15T14:54:53.563 に答える