如何找出什么是拦截’method_missing’

使用Ruby 1.8.6 / Rails 2.3.2

我注意到在我的任何ActiveRecord模型类上调用的任何方法都返回nil而不是NoMethodError。 除了烦人之外,这find_by_name破坏动态查找器( find_by_namefind_by_id等),因为即使存在记录,它们也始终返回nil 。 不从ActiveRecord :: Base派生的标准类不受影响。

有没有办法在ActiveRecord :: Base之前跟踪什么是拦截method_missing?

更新:

切换到1.8.7后,我发现(感谢@MichaelKohl)will_paginate插件首先处理method_missing。 但是will_paginate已经存在了我们的系统(未经改动)很长一段时间,罪魁祸首必须是后来的东西。 任何想法如何看到这个链中的下一步?

更新:

事实certificate,有一个gem(annotate-2.4.0)是猴子修补ActiveRecord::Base#method_missing作为空白方法。 卸载gem解决了我的问题。 虽然没有给出的答案实际上找到了问题,但@Yanhao的答案最接近,因为它只需要一个小调整来发现有问题的别名方法

我认为@Sebi的答案很有帮助,但我想像这样改进它:

 set_trace_func proc { |event, file, line, id, binding, classname| printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname if id.to_s == 'method_missing' } 

结果是这样的:

 ruby-1.8.7-p334 :036 > SomeModel.some_missing_method call /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1873 method_missing ActiveRecord::Base line /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1874 method_missing ActiveRecord::Base line /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1874 method_missing ActiveRecord::Base line /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1981 method_missing ActiveRecord::Base line /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1998 method_missing ActiveRecord::Base c-call /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1998 method_missing Kernel raise /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1998 method_missing ActiveRecord::Base c-return /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1998 method_missing Kernel return /Users/.../.rvm/gems/ruby-1.8.7-p334/gems/activerecord-2.3.12/lib/active_record/base.rb:1998 method_missing ActiveRecord::Base 

你可以试试这个:在rails console中

 set_trace_func proc{ |event, file, line, id, binding, classname| printf("%8s %s:%-2d %10s %8s\n", event, file, line, id, classname) if file =~ /my_app_name/ and event == 'return' #show only interesting files } MyModel.non_existing_method 

输出的最后一行应该是罪魁祸首。

你试过TheModel.method(:method_missing).owner ? 我没有可用的Rails控制台,但请看这个例子:

 >> class MyString < String ; end #=> nil >> MyString.new.method(:method_missing).owner #=> BasicObject 

如您所见,这显示了祖先链中最接近的method_missing定义。

编辑:对不起,没有考虑到你的旧Ruby版本。 在这种情况下,请使用@ aNoble的建议,并查看如何找到在运行时定义方法的位置? 在这种背景下。

使用Ruby调试器 ,在ActiveRecord -call之前插入一个断点,返回nil并开始踩踏。 我认为这优于此处讨论的所有其他解决方案,因为它很容易理解实际发生的事情,并让您更全面地了解导致问题的调用层次结构。 除此之外,这是一项非常普遍的技能,有助于解决许多其他问题。

在Rails控制台中试试这个:

 MyModel.method(:method_missing) 

当然,用您应用中的实际模型替换MyModel 。 它应该告诉哪个类定义了method_missing方法。 如果您使用的是Ruby 1.9,您甚至可以使用MyModel.method(:method_missing).source_location来获取确切的文件和行。