In ein paar unserer produktiven Rails-Anwendungen bei Nix-wie-weg tauchten in den Apache-Logs folgende Meldungen auf:

[...]: warning: Object#id will be deprecated; use Object#object_id

Was die Warnung bedeutet ist relativ klar, wie man aber den Ursprung des Fehlers lokalisieren kann, möchte ich hier kurz vorstellen.

Die Warnung wird grundsätzlich dann geworfen, wenn man auf einem Objekt die Methode #id aufruft, dieses Objekt die Methode aber nicht explizit implementiert. Die Ruby-interne Object#id-Methode ist als "deprecated" markiert. In Rails- bzw. ActiveRecord-Anwendungen kann so ein Aufruf erzeugt werden, wenn man davon ausgeht, auf einem ActiveRecord-Objekt herum zu werkeln, aber eigentlich nil vor sich hat. Auch Rails-Interna machen diesbezüglich wohl selten Abprüfungen.

Aus der Warnmeldung ist die Quelle des Fehlers ist nur selten ersichtlich, weil ein Backtrace fehlt. Genau das habe ich versucht, nachzurüsten. Durch das Ruby-Feature der "offenen Klassen" ist das auch kein Problem. Nach dem Entfernen der #id-Methode wird statt einer Warnung eine Exception geworfen, womit man einen vernünftigen Backtrace erhält. Irgendwo im Environment (environment.rb oder einem Initializer) reicht folgender Code:

   1  Object.send :undef_method, :id

Diese Lösung hat allerdings einen gravierenden Nachteil in der Praxis: Jede Menge Fehlerseiten für die Benutzer der Anwendung! Also ist eine Exception wohl die falsche Wahl. Meine zweite Lösung schreibt einen Backtrace in eine definierte Logdatei und unterdrückt die Warnung.

   1  # config/initializers/log_deprecated_id_calls.rb
   2  
   3  deprecated_id_calls_logfile =
   4    Rails.root.join('log', 'deprecated_id_calls.log', 'a')
   5  deprecated_id_calls_logfile.sync = true
   6  DEPRECATED_ID_CALLS_LOG = Logger.new(deprecated_id_calls_logfile)
   7  
   8  class Object
   9    def id
  10      trace = caller(1)
  11      where = trace[0].sub(/:in.*/,'')
  12      out = "#{where}: Deprecated method #id called"
  13      out += trace[0..10].map{|t| "\tfrom #{t}\n"}.join
  14      DEPRECATED_ID_CALLS_LOG.warn out
  15      object_id
  16    end
  17  end

Die Logausgabe lässt sich über die Logger-Klasse bzw. das Objekt anpassen, zu diesem Thema gibt es ja genügend Ressourcen im Netz.

Ein paar Zeilen meiner Lösung habe ich ebenfalls im Netz gefunden, leider finde ich die Quelle nicht mehr. Falls sie jemand drüberstolpert oder sonstige Anmerkungen oder Fragen hat, der kann sich gerne bei mir melden. So lange ich die Kommentarfunktion im Blog noch nicht ausprogrammiert habe, könnt ihr mich per Mail kontaktieren.

Kommentare

Kommentar abgeben