2012-02-20 14 views
5

El uso de Ruby 1.8.6/2.3.2 CarrilesCómo averiguar lo que está interceptando '' method_missing

estoy notando que cualquier método llamado en cualquiera de mis clases del modelo ActiveRecord está volviendo nil en lugar de un NoMethodError. Además de molesto, esto está rompiendo los buscadores dinámicos (find_by_name, find_by_id, etc.) porque siempre devuelven nil incluso donde existen registros. Las clases estándar que no se derivan de ActiveRecord :: Base no se ven afectadas.

¿Hay alguna manera de rastrear qué está interceptando method_missing antes de ActiveRecord :: Base?

cambio:

Después de cambiar a 1.8.7, he encontrado (gracias a @MichaelKohl) que el plugin will_paginate está manejando method_missing primero. Pero will_paginate ha existido en nuestro sistema (inalterado) durante bastante tiempo y el culpable debe ser algo más adelante en la cadena. ¿Alguna idea de cómo ver qué viene a continuación en esta cadena?

ACTUALIZACIÓN:

Resultó que había una joya (anotar-2.4.0) que era mono parches ActiveRecord::Base#method_missing como un método en blanco. Desinstalar la gema resolvió mi problema. Aunque ninguna de las respuestas dadas encuentra realmente el problema, la respuesta por @Yanhao estuvo más cerca, ya que sólo necesita un pequeño ajuste a descubrir el método infractor alias

Respuesta

4

Creo @ respuesta de Sebi es útil, pero me gustaría mejorar de esta manera:

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

El resultado es la siguiente:

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 
+0

Esta respuesta fue la más cercana excepto que necesitaba expandir la búsqueda a 'if id.to_s = ~/method_missing/'por el método de aliasing – PinnyM

+0

Eso fue Fabolous. +1. Gracias –

0

Prueba esto en la consola de Rails:

MyModel.method(:method_missing) 

Sustitución MyModel con un modelo real en su aplicación, por supuesto. Debería indicar qué clase define el método method_missing. Si está usando Ruby 1.9, puede incluso hacer MyModel.method(:method_missing).source_location para obtener el archivo y la línea exactos.

+0

que devuelve '# '. No estoy seguro de a dónde ir desde allí ... – PinnyM

+0

No es especialmente útil, ¿verdad? Supongo que está siendo definido por alguna meta programación, de lo contrario, creo que le daría el nombre de clase real. ¿Puedes probarlo en Ruby 1.9 y usar 'source_location'? Eso podría ayudarte a encontrar dónde se está definiendo. – aNoble

+0

@aNoble 'method' devuelve un objeto de método, de ahí la firma' method (sym) → method' (pruebe 'MyModel.method (: method_missing) .class' y verá' Method', vea: http: // ruby-doc.org/core-1.9.3/Method.html). Sin embargo, puede invocar métodos en instancias 'Method', ver mi respuesta. –

2

¿Has probado TheModel.method(:method_missing).owner? No tengo ninguna consola de Rails disponibles, pero mira este ejemplo:

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

Como se puede ver esta muestra el method_missing definición más cercana en la cadena de antepasados.

Editar: lo siento, no tuvo en cuenta su versión anterior de Ruby. En ese caso, vaya con la sugerencia de @ aNoble, y también mire How to find where a method is defined at runtime? en este contexto.

+0

¡Gracias por tu ayuda! Pero todavía no estamos allí, eso devuelve 'NoMethodError: método indefinido' owner 'para # ' – PinnyM

+0

Ah, lo siento, olvidé que estás en 1.8.6 :-(Cualquier razón específica por la que están usando una versión tan antigua de Ruby? Vere qué más puedo inventar ... –

+0

Re: versión antigua de Ruby - tenemos la intención de pasar a REE (1.8.7), pero aún no hemos llegado a eso aún :) – PinnyM

3

Usted podría intentar esto: En los carriles consola

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 

La última línea de la salida debería ser el culpable.

+0

Muy cerca, excepto que el método ofensivo no estaba realmente en mi aplicación y no se incluyó en la salida - vea la respuesta de @ Yanhao – PinnyM

2

Utilice el Ruby debugger, inserte un punto de interrupción antes de ActiveRecord -llama que devuelve nil y comience a abrirse paso. Creo que esto es superior a todas las demás soluciones que se analizan aquí, porque es fácil entender lo que realmente está sucediendo y le da una comprensión más profunda de la jerarquía de llamadas que causa su problema. Aparte de eso, es una habilidad bastante universal que ayuda a resolver muchos otros problemas.

Cuestiones relacionadas