Frage

Ich baue ein Rails 3-Gem, das die von einer ActiveRecord-Abfrage zurückgegebenen Datensätze im Wesentlichen ändert.Eines der Dinge, die ich mache, ist das Überschreiben method_missing Und respond_to? Methoden, aber es scheint, dass meine respond_to? Definition führt zu einer Endlosschleife, die einen „SystemStackError:Fehler „Stapelebene zu tief“.

Hier sind meine ursprünglichen Definitionen dieser Methoden:

def respond_to?(name, *args)
  super(name, *args) || parent_association.respond_to?(name)
end

def method_missing(name, *args, &block)
  if parent_association.respond_to?(name)
    parent_association.send(name, *args, &block)
  else
    super(name, *args, &block)
  end
end

def parent_association
  send(parent_association_name)  # Essentially yields another ActiveRecord
                                 # instance (e.g.: instance of User), but
                                 # never returns itself.
end

Als ich versuchte herauszufinden, warum es zu dieser Endlosschleife kam, habe ich eine Umstrukturierung vorgenommen respond_to? mit einigen „Vorher“- und „Nachher“-Ausgaben, um zu sehen, wo es hängen bleibt.

def respond_to?(name, *args)
  return true if super(name, *args)
  puts "before (#{name})"
  result = parent_association.respond_to?(name)
  puts "after"
  result
end

Bei der Ausführung scheint es, dass verschiedene Rückrufe und Attributmethoden wie erwartet ausgeführt werden, mit jeweils einem einzigen Vorher- und Nachher-Aufruf:

before (_run__374051839217347232__initialize__1707831318230746190__callbacks)
after
before (_run__374051839217347232__validation__1707831318230746190__callbacks)
after
before (_run__374051839217347232__validate__1707831318230746190__callbacks)
after
before (_run__374051839217347232__save__1707831318230746190__callbacks)
after
before (_run__374051839217347232__create__1707831318230746190__callbacks)
after
before (created_at)
after
before (created_on)
after
...

Jedes Mal, wenn ich jedoch einen Find-Rückruf sehe, scheint dieser in einer Endlosschleife gefangen zu sein:

before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
...
SystemStackError: stack level too deep

Wenn ich meine hacke respond_to?, dann scheint alles reibungslos zu laufen:

def respond_to?(name, *args)
  return true if super(name, *args)
  return false if name =~ /^_run_.*_find_.*_callbacks$/
  parent_association.respond_to?(name)
end

Was mache ich falsch, dass ich diesen Hack anscheinend brauche?Und wie kann ich es vermeiden?

War es hilfreich?

Lösung 2

Das Problem war letztendlich diese Funktion:

def parent_association
  send(parent_association_name)  # Essentially yields another ActiveRecord
                                 # instance (e.g.: instance of User), but
                                 # never returns itself.
end

Die Variable parent_association_name ist so etwas wie employee, was durch etwas wie Folgendes definiert wird:

belongs_to :employee

Weil employee wird auf der Modellinstanz erst definiert, NACHDEM der Suchrückruf ausgeführt wurde und weil ich zum ersten Mal aufgerufen habe respond_to? an einer Stelle, BEVOR der Find-Rückruf aufgerufen wird (in Code Nr. in meiner ursprünglichen Frage enthalten), der Aufruf von send(parent_assocation_name) verursachte einen rekursiven Aufruf von respond_to?.

Andere Tipps

Wenn parent_association ein neues AR-Objekt zurückgibt, erbt es auch Ihren Hack, sodass der generationspflichtige respond_to? aufrufen wird, wodurch Ihr generationstätiges Objektcode aufgerufen wird, der ein AR neues Objekt erstellt usw.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top