Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find out what is intercepting 'method_missing'

Using Ruby 1.8.6 / Rails 2.3.2

I am noticing that any method called on any of my ActiveRecord model classes is returning nil instead of a NoMethodError. Besides annoying, this is breaking the dynamic finders (find_by_name, find_by_id, etc.) because they always return nil even where records exist. Standard classes that don't derive from ActiveRecord::Base aren't affected.

Is there a way to track down what is intercepting method_missing before ActiveRecord::Base?

UPDATE:

After switching to 1.8.7, I have found (thanks to @MichaelKohl) that the will_paginate plugin is handling method_missing first. But will_paginate has been around in our system (unaltered) for quite a while and the culprit must be something later up the chain. Any ideas how to see what comes next in this chain?

UPDATE:

It turned out that there was a gem (annotate-2.4.0) that was monkey patching ActiveRecord::Base#method_missing as a blank method. Uninstalling the gem solved my problem. Although none of the answers given actually found the problem, the answer by @Yanhao came closest as it only needed a minor tweak to discover the offending aliased method

like image 800
PinnyM Avatar asked Feb 20 '12 16:02

PinnyM


4 Answers

I think @Sebi's answer is helpful, but I'd like to improve it like this:

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'
}

The result is like this:

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
like image 62
Yanhao Avatar answered Sep 27 '22 23:09

Yanhao


You could try this : In 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

The last line of the output should be the culprit.

like image 26
Sebi Avatar answered Sep 30 '22 23:09

Sebi


Have you tried TheModel.method(:method_missing).owner? I have no Rails console available, but look at this example:

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

As you can see this shows you the closest method_missing definition in the ancestors chain.

Edit: sorry, didn't take into account your old Ruby version. In that case, go with @aNoble's suggestion, and also look at How to find where a method is defined at runtime? in this context.

like image 37
Michael Kohl Avatar answered Sep 28 '22 23:09

Michael Kohl


Use the Ruby debugger, insert a breakpoint before an ActiveRecord-call that returns nil and start stepping your way through. I think this is superior to all other solutions discussed here, because it's easy to understand what's really going on and gives you a more thorough understanding of the call hierarchy that causes your problem. Apart from that, it's quite an universal skill that helps solving many other problems.

like image 36
jupp0r Avatar answered Oct 01 '22 23:10

jupp0r