如何找出拦截'method_missing'的内容

时间:2012-02-20 16:33:24

标签: ruby-on-rails ruby

使用Ruby 1.8.6 / Rails 2.3.2

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

有没有办法在ActiveRecord :: Base之前找到拦截method_missing的内容?

更新

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

更新

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

5 个答案:

答案 0 :(得分:4)

我认为@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

答案 1 :(得分:3)

你可以试试这个: 在rails控制台

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

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

答案 2 :(得分:2)

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

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

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

编辑:抱歉,没有考虑到您的旧Ruby版本。在这种情况下,请使用@ aNoble的建议,并在此上下文中查看How to find where a method is defined at runtime?

答案 3 :(得分:2)

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

答案 4 :(得分:0)

在Rails控制台中试试这个:

MyModel.method(:method_missing)

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