2

これは別の問題の再投稿であり、今回はより分離されています。私の environment.rb ファイルで、次の行を変更しました。

config.time_zone = 'UTC'

この行に:

config.active_record.default_timezone = :utc

それ以来、この呼び出し:

Category.find(1).subcategories.map(&:id)

config.cache_classes = false の場合、開発環境で 2 回目に実行すると、「スタック レベルが深すぎます」というエラーで失敗します。config.cache_classes = true の場合、問題は発生しません。このエラーは、active_record/attribute_methods.rb の 252 行付近の次のコードの結果です。

def method_missing(method_id, *args, &block)
...

    if self.class.primary_key.to_s == method_name
        id
    ....

「id」関数の呼び出しは method_missing を再呼び出しし、id が何度も呼び出されるのを防ぐものは何もないため、スタック レベルが深すぎます。

Rails 2.3.8 を使用しています。カテゴリ モデルには、サブカテゴリが多数あります。呼び出しは、上記の行のバリアント (たとえば、Category.first.subcategory_ids、"map" ではなく "each" の使用など) で失敗します。

どんな考えでも大歓迎です。

ありがとう!アミット

4

2 に答える 2

4

これは解決されましたが、私はこれに参加し、この問題をどのように修正したかを報告したかっただけです。OPと同じ症状があり、最初のリクエスト.id()は正常に機能し、後続のリクエスト.id()は「スタックが深すぎます」というエラーメッセージをスローしました。通常、どこかに無限ループがあることを意味するため、これは奇妙なエラーです。私はこれを変更して修正しました:

config.action_controller.perform_caching = true
config.cache_classes                     = false

config.action_controller.perform_caching = true
config.cache_classes                     = true

環境/ production.rb にあります。

更新: この問題の根本原因は cache_store であることが判明しました。デフォルトの MemoryStore は ActiveRecord モデルを保持しません。これはかなり古いバグであり、かなり深刻です。なぜ修正されていないのかわかりません。とにかく、回避策は別の cache_store を使用することです。config/environments/development.rb でこれを使用してみてください:

config.cache_store = :file_store

更新 #2: C. Bedard がこの問題の分析を投稿しました。うまくまとまりそうです。

私自身、この問題に遭遇した (そして何度も行き詰まった) ため、エラーを調査しました (うまくいけば、適切な修正が見つかりました)。これについて私が知っていることは次のとおりです。 ActiveRecord::Base#reset_subclasses がリクエスト間でディスパッチャーによって呼び出されたときに発生します (開発モードのみ)。

ActiveRecord::Base#reset_subclasses は、inheritable_attributes ハッシュ (#skip_time_zone_conversion_for_attributes が格納されている場所) を消去します。これは、#1290 の「monkey test app」が示すように、リクエストを通じて永続化されたオブジェクトで発生するだけでなく、AR で生成された関連付けメソッドにアクセスしようとしたときにも、現在のリクエストでのみ存在するオブジェクトに対しても発生します。

このバグは、#skip_time_zone_conversion_for_attributes 宣言が base.cattr_accessor から base.class_inheritable_accessor に変更されたこのコミットによって導入されました。しかし、繰り返しになりますが、その同じコミットは別のものも修正しました。ここで最初に提出されたパッチは、reset_subclasses の instance_variables と instance_methods のクリアを単純に回避するだけで、大量のリークを引き起こします。リーク量は、アプリの複雑さ (つまり、それぞれのモデル、関連付け、および属性の数) に正比例するようです。パッチが適用されると、開発モードでの各リクエストで約 1Mb リークするかなり複雑なアプリがあります。したがって、実行可能ではありません(とにかく私にとって)。

これを解決するためのさまざまな方法を試しながら、最初のエラー (2 回目のリクエストで skip_time_zone_conversion_for_attributes が nil である) を修正しましたが、別のエラーが発見されました (最初の例外が発生する前に発生したため、発生しませんでした)。このエラーは、#774 (「id」メソッドの method_missing でのスタック オーバーフロー) で報告されたエラーのようです。

さて、解決策として、私のパッチ (添付) は次のことを行います: #skip_time_zone_conversion_for_attributes メソッドのラッパー メソッドを追加し、値を常に class_inheritable_attribute として読み書きするようにします。このように、 nil はもう返されません。

reset_subclasses が呼び出されたときに「id」メソッドが消去されないようにします。AR は、最初にソースで直接定義しますが、最初に呼び出されたときに #define_read_method で再定義するため、ちょっと奇妙です。そして、それがまさにリロード後に失敗する原因です(reset_subclassesがそれを一掃するため)。

また、reload_models_test.rb にテストを追加しました。このテストは、reset_subclasses を呼び出して、開発モードでのリクエスト間のリロードを試行およびシミュレートします。この時点で私が判断できないのは、ライブ ディスパッチャ リクエスト サイクルで行うように、実際にリロード メカニズムがトリガーされるかどうかです。スクリプト/サーバーからもテストしましたが、エラーはなくなりました。

長い貼り付けで申し訳ありません。Rails lighthouse プロジェクトが非公開であることは残念です。上記のパッチは非公開です。

于 2011-05-26T15:57:58.437 に答える
2

-この回答は、私の元の投稿からコピーされています

ついに解決!3番目の質問を投稿した後、 trptcolinの助けを借りて、私は実用的な解決策を確認することができました。

問題:requireテーブルレスモデル(アプリ/モデルにはあるがActiveRecord :: Baseを拡張しないクラス)内のモデルを含めるために使用していました。たとえば、をFilterCategory実行するクラスがありましrequire 'category'た。これは、Railsのクラスキャッシングを台無しにしました。requireそもそもCategory.find :all失敗などの行があったので使わなければなりませんでした。

解決策(クレジットはtrptcolinに送られます):。に置き換えCategory.find :allます::Category.find :all。これは、モデルを明示的に要求する必要なしに機能するため、クラスキャッシュの問題は発生しません。

「スタックが深すぎる」​​問題は、使用時にも解消されますconfig.active_record.default_timezone = :utc

于 2010-11-11T04:46:24.793 に答える