Ruby on rails 铁轨:;“堆栈级别太深”;调用“时出错”;id";主键法

Ruby on rails 铁轨:;“堆栈级别太深”;调用“时出错”;id";主键法,ruby-on-rails,activerecord,method-missing,Ruby On Rails,Activerecord,Method Missing,这是一个重新发布,这次更好的隔离。 在我的environment.rb文件中,我更改了以下行: config.time_zone = 'UTC' config.active_record.default_timezone = :utc 关于这一行: config.time_zone = 'UTC' config.active_record.default_timezone = :utc 从那时起,这个电话: Category.find(1).subcategories.map(&

这是一个重新发布,这次更好的隔离。 在我的environment.rb文件中,我更改了以下行:

config.time_zone = 'UTC'
config.active_record.default_timezone = :utc
关于这一行:

config.time_zone = 'UTC'
config.active_record.default_timezone = :utc
从那时起,这个电话:

Category.find(1).subcategories.map(&:id)
当config.cache_classes=false时,在开发环境中第二次运行“堆栈级别太深”错误时失败。如果config.cache_classes=true,则不会出现问题。 该错误是第252行附近的active_record/attribute_methods.rb中的以下代码导致的:

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

    if self.class.primary_key.to_s == method_name
        id
    ....
对“id”函数的调用重新调用方法_missing,并且没有任何东西可以阻止反复调用id,从而导致堆栈级别太深

我使用的是Rails 2.3.8。 类别模型有许多子类别。 上述行的变体调用失败(例如Category.first.subcategory_id,使用“each”而不是“map”等)

任何想法都将受到高度赞赏

谢谢! Amit

——这个答案是从我原来的帖子中抄来的

终于解决了! 发布后,在的帮助下,我可以确认一个有效的解决方案

问题:我使用了
require
来包含无表模型中的模型(在app/models中但不扩展ActiveRecord::Base的类)。例如,我有一个类
FilterCategory
,它执行
require'category'
。这破坏了Rails的类缓存。 我必须首先使用
require
,因为像
Category.find:all
这样的行失败了

解决方案(归功于trptcolin):将
Category.find:all
替换为
:Category.find:all
。这不需要显式地要求任何模型,因此不会导致任何类缓存问题


使用
config.active\u record.default\u timezone=:utc时,“堆栈太深”问题也会消失,即使这一问题已经解决,我还是想插话,并报告我是如何解决这个问题的。我的症状与OP相同,initial request.id()工作正常,后续requests.id()会抛出“stack too deep”错误消息。这是一个奇怪的错误,因为它通常意味着在某个地方有一个无限循环。我通过更改以下内容来修复此问题:

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

在environments/production.rb中

更新:这个问题的根本原因是缓存存储。默认MemoryStore不会保留ActiveRecord模型。这是一个相当老的错误,相当严重,我不知道为什么它没有被修复。无论如何,解决方法是使用不同的缓存存储。尝试在您的config/environments/development.rb中使用此选项:

config.cache_store = :file_store
更新#2:C.贝达德发表了对该问题的分析。似乎很好地总结了一下

我自己也遇到了这个问题(并且一直被困在这个问题上),我已经调查了这个错误(并希望找到一个好的修复方法)。以下是我对它的了解: 当调度程序在请求之间调用ActiveRecord::Base#reset_子类时(仅在开发模式下),就会发生这种情况

ActiveRecord::Base#reset#子类清除可继承的#属性哈希(其中存储了#跳过#时区#转换"属性)。 它不仅会发生在通过请求持久化的对象上(如#1290中的“monkey test app”所示),而且在尝试访问AR上生成的关联方法时也会发生,即使是仅存在于当前请求上的对象

此错误是由以下情况引起的:将用于属性声明的#skip_time_zone_conversion_从base.cattr_访问器更改为base.class_inheritable_访问器。但是,同样的承诺也解决了其他问题。 最初在这里提交的补丁只需避免清除reset_子类中的instance_变量和instance_方法,就会导致大量泄漏,泄漏量似乎与应用程序的复杂性成正比(即每个应用程序上的模型、关联和属性数)。我有一个相当复杂的应用程序,当应用补丁时,在开发模式下,每个请求都会泄漏将近1Mb的内存。所以这是不可行的(对我来说)

在尝试不同的方法来解决这个问题时,我已经纠正了初始错误(跳过\u时区\u转换\u,在第二次请求时属性为零),但它发现了另一个错误(这只是没有发生,因为第一个异常会在到达它之前引发)。该错误似乎是#774中报告的错误(“id”方法缺少方法_中的堆栈溢出)

现在,对于解决方案,我的修补程序(附件)执行以下操作: 它为#skip_time_zone_conversion_for _attributes方法添加包装器方法,确保它始终以类_可继承_属性的形式读取/写入值。这样,nil就再也不会返回了

它确保在调用reset_子类时不会删除“id”方法。AR在这一点上有点奇怪,因为它首先直接在源代码中定义它,但在第一次调用它时用#define_read_方法重新定义它自己。这正是它在重新加载后失败的原因(因为reset_子类会将其清除)

我还在reload_models_test.rb中添加了一个测试,它调用reset_子类来尝试和模拟在dev模式下请求之间的重新加载。此时我无法确定的是,它是否真的像在实时调度程序请求周期中那样触发了重新加载机制。我还从脚本/服务器进行了测试,错误消失了


很抱歉粘贴太长,rails灯塔项目是私人的,这太糟糕了。上面提到的补丁是私有的。

您使用的是哪个版本的ruby?它是私有的,意味着您无法访问它?或者你不能共享它?“Private”意思是当我写这篇文章时,管理员关闭了lighthouse项目并迁移到Github。所有的旧内容都被隐藏了。奇怪的是,它现在是开放的,而且票可以