2012-02-20 12 views
5

Utilizzando rubino 1.8.6/Rails 2.3.2Come scoprire che cosa sta intercettando 'method_missing'

Sto notando che qualsiasi metodo chiamato su uno dei miei classi del modello ActiveRecord sta tornando nil al posto di un NoMethodError. Oltre a infastidire, questo è rompere i cercatori dinamici (find_by_name, find_by_id, ecc.) Perché restituiscono sempre nil anche dove esistono i record. Le classi standard che non derivano da ActiveRecord :: Base non sono interessate.

C'è un modo per rintracciare cosa intercetta method_missing prima di ActiveRecord :: Base?

UPDATE:

Dopo il passaggio alla 1.8.7, ho trovato (grazie a @MichaelKohl) che il plug will_paginate sta gestendo method_missing prima. Ma will_paginate è rimasto nel nostro sistema (inalterato) per un po 'di tempo e il colpevole deve essere qualcosa più avanti nella catena. Qualche idea su come vedere cosa viene dopo in questa catena?

UPDATE:

Si è scoperto che c'era una gemma (annotare-2.4.0), che era scimmia patching ActiveRecord::Base#method_missing come metodo vuoto. La disinstallazione della gemma ha risolto il mio problema. Anche se nessuna delle risposte fornite effettivamente trovato il problema, la risposta @Yanhao si avvicinava di più in quanto necessario solo un tweak minore per scoprire il metodo incriminato alias

risposta

4

Penso @ risposta di Sebi è utile, ma mi piacerebbe migliorare in questo modo:

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

Il risultato è simile a questo:

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

Questa risposta è stata la più vicina tranne che avevo bisogno di espandere la ricerca a 'if id.to_s = ~/method_missing/'a causa del metodo aliasing – PinnyM

+0

Questo era Fabolous. +1. Grazie –

0

Prova questo nella console Rails:

MyModel.method(:method_missing) 

Sostituzione MyModel con un modello reale nella tua app, ovviamente. Dovrebbe indicare quale classe definisce il metodo method_missing. Se stai usando Ruby 1.9 puoi anche fare MyModel.method(:method_missing).source_location per ottenere il file e la linea esatti.

+0

che restituisce '# '. Non sono sicuro di dove andare da lì ... – PinnyM

+0

Non particolarmente utile, è così. Immagino che sia stato definito da qualche meta-programmazione, altrimenti penserei che ti darebbe il nome effettivo della classe. Puoi provarlo in Ruby 1.9 e usare 'source_location'? Questo potrebbe aiutarti a trovare dove viene definito. – aNoble

+0

@aNoble 'metodo' restituisce un oggetto metodo, da cui la firma' metodo (sym) → metodo' (prova 'MyModel.method (: method_missing) .class' e vedrai' Metodo', vedi: http: // ruby-doc.org/core-1.9.3/Method.html). Puoi comunque invocare metodi su istanze di 'Metodo', vedi la mia risposta. –

2

Hai provato TheModel.method(:method_missing).owner? Non ho console Rails a disposizione, ma guarda questo esempio:

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

Come si può vedere questa mostra la method_missing definizione più vicino nella catena antenati.

Modifica: scusa, non ho preso in considerazione la tua vecchia versione di Ruby. In questo caso, segui il suggerimento di @ a Noble e guarda anche How to find where a method is defined at runtime? in questo contesto.

+0

Grazie per il tuo aiuto! Ma non siamo ancora arrivati ​​- restituisce 'NoMethodError: metodo non definito' owner 'per # ' – PinnyM

+0

Ah, scusa, ho dimenticato che sei 1.8.6 :-(Qualche ragione specifica per te sto usando una versione vecchia di Ruby? Vedrò cos'altro posso inventare ... –

+0

Re: vecchia versione di Ruby - intendiamo andare su REE (1.8.7), ma non ci siamo ancora riusciti ancora :) – PinnyM

3

Si potrebbe provare questo: 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 

L'ultima riga l'uscita dovrebbe essere il colpevole.

+0

Abbastanza vicino, tranne che il metodo incriminato non era effettivamente nella mia applicazione e non era incluso nell'output - vedere @ Risposta di Yanhao – PinnyM

2

Utilizzare Ruby debugger, inserire un punto di interruzione prima di una chiamata ActiveRecord che restituisce nil e iniziare a farsi strada. Penso che questo sia superiore a tutte le altre soluzioni discusse qui, perché è facile capire cosa sta realmente accadendo e ti dà una comprensione più approfondita della gerarchia di chiamata che causa il tuo problema. A parte questo, è un'abilità abbastanza universale che aiuta a risolvere molti altri problemi.

Problemi correlati