29 Stimmen

Verwendung des after_save-Callbacks zur Änderung desselben Objekts, ohne den Callback erneut auszulösen (Rekursion)

Wenn ich einem ActiveRecord-Modell einen after_save-Callback hinzufüge und bei diesem Callback update_attribute verwende, um das Objekt zu ändern, wird der Callback erneut aufgerufen, und es kommt zu einem "Stack Overflow" (hehe, konnte nicht widerstehen).

Ist es möglich, dieses Verhalten zu vermeiden, vielleicht Deaktivieren des Rückrufs während seiner Ausführung? Oder gibt es einen anderen Ansatz?

Gracias.

13voto

Groxx Punkte 2469

Eine Abhilfe besteht darin, eine Variable in der Klasse zu setzen und ihren Wert in der after_save-Datei zu überprüfen.

  1. Prüfen Sie es zuerst. (wenn var)
  2. Weisen Sie ihm einen "false"-Wert zu, bevor Sie update_attribute aufrufen.
  3. update_attribute aufrufen.
  4. Weisen Sie ihm einen 'true'-Wert zu.
  5. Ende

Auf diese Weise wird nur zweimal versucht zu speichern. Dies wird wahrscheinlich zweimal auf Ihre Datenbank zugreifen, was wünschenswert sein kann oder auch nicht.

Ich habe das vage Gefühl, dass da etwas eingebaut ist, aber das ist eine ziemlich narrensichere Methode, um einen bestimmten Punkt der Rekursion in so ziemlich jeder Anwendung zu verhindern. Ich würde auch empfehlen, sich den Code noch einmal anzuschauen, da es wahrscheinlich ist, dass alles, was Sie in after_save tun, auch in before_save getan werden sollte. Es kann vorkommen, dass dies nicht der Fall ist, aber das ist eher selten.

11voto

srboisvert Punkte 12579

Können Sie stattdessen den before_save-Callback verwenden?

11voto

Walt Jones Punkte 1253

Ich habe diese Antwort nicht gesehen, also dachte ich, ich würde sie hinzufügen, falls sie jemandem hilft, der nach diesem Thema sucht. (ScottDs Vorschlag without_callbacks ist nahe dran.)

ActiveRecord bietet update_without_callbacks für diese Situation, aber es ist eine private Methode. Verwenden Sie send, um trotzdem Zugriff darauf zu erhalten. Als innerhalb eines Rückrufs für das Objekt, das Sie speichern, ist genau der Grund, dies zu verwenden.

Es gibt auch einen anderen SO-Thread hier, der dies ziemlich gut behandelt: Wie kann ich die Ausführung von ActiveRecord-Callbacks vermeiden?

7voto

scottd Punkte 7004

Sie können sich auch das Plugin Ohne_Rückrufe . Es fügt AR eine Methode hinzu, mit der Sie bestimmte Rückrufe für einen bestimmten Block überspringen können. Beispiel:

def your_after_save_func
  YourModel.without_callbacks(:your_after_save_func) do
    Your updates/changes
  end
end

6voto

Terry G Lorber Punkte 2852

Prüfen Sie, wie aktualisieren_attribut implementiert ist. Verwenden Sie stattdessen die Sendemethode:

send(name.to_s + '=', value)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X