この効果は書き方によるものだと思いますActionController::Reloader
。ActionController::Reloader#call
これは 2.3.3のものです。コメントに注意してください。
def call(env)
Dispatcher.reload_application
status, headers, body = @app.call(env)
# We do not want to call 'cleanup_application' in an ensure block
# because the returned Rack response body may lazily generate its data. This
# is for example the case if one calls
#
# render :text => lambda { ... code here which refers to application models ... }
#
# in an ActionController.
#
# Instead, we will want to cleanup the application code after the request is
# completely finished. So we wrap the body in a BodyWrapper class so that
# when the Rack handler calls #close during the end of the request, we get to
# run our cleanup code.
[status, headers, BodyWrapper.new(body)]
end
Dispatcher.reload_application
自動ロードされた定数を削除しませんDispatcher.cleanup_application
。BodyWrapper#close
考えられる例外を念頭に置いて書かれています。
def close
@body.close if @body.respond_to?(:close)
ensure
Dispatcher.cleanup_application
end
ただし、例外がスローされた場合@app.call
、インスタンス化されず、呼び出されないため、これは役に立ちません。ActionController::Reloader#call
BodyWrapper
Dispatcher.cleanup_application
次のシナリオを想像してください。
- API 呼び出しに影響するファイルの 1 つを変更します
- API 呼び出しを実行するとエラーが表示されます。この時点で、バグのあるファイルを含むすべてのファイルがアンロードされません。
- コード修正を行い、同じAPI 呼び出しを実行して、機能するかどうかを確認します
- 呼び出しは、以前と同じ方法で、古いクラス/オブジェクト/モジュールにルーティングされます。これは同じエラーをスローし、ロードされた定数をメモリに残します
これは、従来のコントローラがエラーを発生させた場合には発生しません。これらは によって処理されるためActionController::Rescue
です。このような例外はヒットしませんActionController::Reloader
。
最も簡単な解決策は、フォールバック レスキュー句を API ルーティング ミドルウェアに配置することです。これにはいくつかのバリエーションがあります。
def call(env)
# route API call
resuce Exception
Dispatcher.cleanup_application
raise
end
これは 3 年前の質問に対する私の回答であり、2.3.3 のコール スタックに従っていることに注意してください。レールの新しいバージョンでは、処理が異なる場合があります。