2

这是另一个问题的转贴,这次最好隔离。在我的 environment.rb 文件中,我更改了这一行:

config.time_zone = 'UTC'

到这一行:

config.active_record.default_timezone = :utc

从那以后,这个电话:

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

当 config.cache_classes = false 时,在开发环境中第二次运行后出现“堆栈级别太深”错误。如果 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 模型 has_many :subcategories。该调用在上述行的变体上失败(例如 Category.first.subcategory_ids,使用“each”而不是“map”等)。

任何想法将不胜感激。

谢谢!阿米特

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 中的“猴子测试应用程序”所示,而且在尝试访问 AR 上生成的关联方法时也会发生,即使对于仅存在于当前请求的对象也是如此。

此提交引入了此错误,其中 #skip_time_zone_conversion_for_attributes 声明从 base.cattr_accessor 更改为 base.class_inheritable_accessor。但话又说回来,同样的提交也修复了其他问题。最初在这里提交的补丁只是避免清除 reset_subclasses 中的 instance_variables 和 instance_methods 确实会引入大量泄漏,并且泄漏的数量似乎与应用程序的复杂性成正比(即每个模型、关联和属性的数量)。我有一个非常复杂的应用程序,当应用补丁时,它在开发模式下的每个请求都会泄漏近 1Mb。所以它不可行(无论如何对我来说)。

在尝试不同的方法来解决这个问题时,我已经纠正了最初的错误(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 灯塔项目是私有的,这很糟糕。上面提到的补丁是私有的。

于 2011-05-26T15:57:58.437 回答
2

- 这个答案是从我原来的帖子复制过来

终于解决了!在发布第三个问题并在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 回答