2

Rails 3.2.14 で正常に動作していた Rails アプリケーションがあります。Railscast のエピソード 415に従って、Rails 4 へのアップグレードに取り組み始めたところです。

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 > 

nameRails 3.2.14 では、属性が意図どおりに設定されていることに気付くでしょう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 に答える