Как узнать, что перехватывает 'method_missing' - PullRequest
5 голосов
/ 20 февраля 2012

Использование Ruby 1.8.6 / Rails 2.3.2

Я замечаю, что любой метод, вызываемый в любом из моих классов модели ActiveRecord, возвращает nil вместо NoMethodError. Помимо раздражения, это нарушает динамические искатели (find_by_name, find_by_id и т. Д.), Потому что они всегда возвращают nil даже там, где существуют записи. Стандартные классы, которые не являются производными от ActiveRecord :: Base, не затрагиваются.

Есть ли способ отследить, что перехватывает method_missing перед ActiveRecord :: Base?

UPDATE:

После перехода на 1.8.7 я обнаружил (благодаря @MichaelKohl), что плагин will_paginate сначала обрабатывает method_missing. Но will_paginate уже давно существует в нашей системе (без изменений), и виновник должен быть чем-то более поздним. Есть идеи, как увидеть, что будет дальше в этой цепочке?

UPDATE:

Оказалось, что был драгоценный камень (annotate-2.4.0), который обезьяна исправляла ActiveRecord::Base#method_missing как пустой метод. Удаление драгоценного камня решило мою проблему. Хотя ни один из приведенных ответов на самом деле не нашел проблему, ответ @Yanhao был наиболее близким, так как для обнаружения оскорбительного метода с псевдонимом потребовалась лишь небольшая настройка

Ответы [ 5 ]

4 голосов
/ 26 февраля 2012

Я думаю, что ответ @ Себи полезен, но я бы хотел улучшить его следующим образом:

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
3 голосов
/ 25 февраля 2012

Вы можете попробовать это: В консоли 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 голосов
/ 25 февраля 2012

Используйте Ruby отладчик , вставьте точку останова перед ActiveRecord -колоколом, который возвращает nil, и начните проходить через него.Я думаю, что это превосходит все другие решения, обсуждаемые здесь, потому что легко понять, что происходит на самом деле, и дает вам более глубокое понимание иерархии вызовов, которая вызывает вашу проблему.Кроме того, это довольно универсальный навык, который помогает решать многие другие проблемы.

2 голосов
/ 23 февраля 2012

Вы пробовали TheModel.method(:method_missing).owner? У меня нет доступной консоли Rails, но посмотрите на этот пример:

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

Как вы можете видеть, это показывает вам самое близкое определение method_missing в цепочке предков.

Редактировать: извините, не принял во внимание вашу старую версию Ruby. В этом случае, воспользуйтесь предложением @ aNoble, а также посмотрите на Как найти, где метод определяется во время выполнения? в этом контексте.

0 голосов
/ 20 февраля 2012

Попробуйте это в консоли Rails:

MyModel.method(:method_missing)

Замена MyModel реальной моделью в вашем приложении, конечно.Он должен сказать, какой класс определяет метод method_missing.Если вы используете Ruby 1.9, вы можете даже MyModel.method(:method_missing).source_location получить точный файл и строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...