2

我有一个在 Rails 3.2.14 上运行良好的 Rails 应用程序。我刚刚开始着手将它升级到 Rails 4,基本上是跟随Railscast 第 415 集

我到了尝试运行 rspec 测试的部分,现在发现许多失败并出现以下错误:

 Failure/Error: Unable to find matching line from backtrace
 SystemStackError:
   stack level too deep

我还检查了我的 Cucumber 测试并发现了类似的失败。

stack level too deep (SystemStackError)

由于在我开始升级之前一切都很好,所以我一直在寻找其他类似但没有找到的体验。

我已经尝试过 Ruby 1.9 和 2.0。我没有修改任何代码

任何指导表示赞赏。

更新:

我已将问题追溯到一个模型,该模型定义method_missing为其实现的一部分。我已经在单独的答案中描述了我发现的内容,以便可以单独对其进行评论。

我的应用程序包含一个实现自己的模型,method_missing这可能会导致递归循环,最终导致“堆栈级别到深”错误。

4

2 回答 2

3

根据建议,有足够的细节来保证将其作为答案分开。

我已经将问题追溯到一个模型,该模型定义method_missing为其实现的一部分。我发现,如果method_missing模型中有定义,则调用它而不是任何访问器。这会导致任何模型设置失败。

(在我的特定情况下,定义了 method_missing ,这就是导致我最初提到的堆栈溢出的原因)。

我可以通过在 Rails 3.2.14 中定义一个新的 rails 应用程序然后创建一个新模型来简洁地重现该问题:

class Item < ActiveRecord::Base
  attr_accessible :name, :content
  store :content

  def method_missing(id, *args) 
    puts "method missing: #{id}"
  end
end

以及相关的迁移

class CreateItems < ActiveRecord::Migration
  def change
    create_table :items do |t|
      t.string :name
      t.text :content

      t.timestamps
    end
  end
end

如果我运行 rails 控制台,我可以练习模型:

$ rails console
Loading development environment (Rails 3.2.14)
2.0.0p247 :001 > x = Item.new(name: 'foo')
 => #<Item id: nil, name: "foo", content: {}, created_at: nil, updated_at: nil> 
2.0.0p247 :002 >

如果我在 Rails 4.0.0 中构建完全相同的东西,我会得到不同的输出:

$ rails console
Loading development environment (Rails 4.0.0)
2.0.0p247 :001 > x = Item.new(name: 'foo')
method missing: name=
 => #<Item id: nil, name: nil, content: {}, created_at: nil, updated_at: nil> 
2.0.0p247 :002 > 

您会注意到,在 Rails 3.2.14 中,该name属性被设置foo为意图。然而,在 Rails 4.0.0 中,看到它method_missing被调用并且属性没有被设置。

我正在阅读对 ActiveRecord 的更改,但我找不到任何表明method_missing在 Rails 4 之前使用的模型在 Rails 4 中不再适用的任何内容。

任何使代码示例能够在 Rails 4 中运行的指针都将帮助我解决我的模型遇到的问题。

更新

通过手动调用向上method_missing链,我可以让上面的例子工作:

  def method_missing(id, *args) 
    super
    if respond_to? id
      send(id,*args)
    else
      puts "method missing: #{id}"
    end 
  end 

需要这样做对我来说感觉不对,因为不清楚为什么这种行为在 Rails 3 和 4 之间发生了变化。我觉得我错过了其他东西......

于 2013-08-21T22:02:21.183 回答
1

我也不知道更改是什么,但是您可以通过检查来避免为非访问器方法调用 super respond_to_without_attributes?。这在源代码中使用

  def method_missing(method, *args) 
    super if respond_to_without_attributes?(method, true) # returns true when attr accessors

    if respond_to? method
      send(method,*args)
    else
      puts "method missing: #{method}"
    end 
  end 
于 2013-11-26T00:08:41.630 回答