Empfangen "Ausnahme eines veralteten Objekts versucht: Benutzer" beim Aktualisieren von current_user vor dem Abmelden

8

Ich habe optimistisches Sperren für mein Benutzermodell aktiviert, um mögliche Konflikte in verschiedenen Teilen meiner Codebasis zu behandeln. Ich habe jedoch einen unerwarteten Konflikt und ich weiß nicht, wie ich damit umgehen soll, weil ich nicht weiß, was das verursacht.

Ich verwende das Juwel "Devise" zur Authentifizierung und verwende die Methode "before_logout", um ein Sicherheitstoken zurückzusetzen ...

%Vor%

Ich bin neu bei Rails (nur ein paar Wochen), also weiß ich nicht wirklich wo sonst in meinem Code nachzusehen oder warum dieser Code die Ausnahme auslöst. Irgendwelche Vorschläge oder Ideen werden sehr geschätzt.

Vielen Dank im Voraus für Ihre Weisheit!

    
BeachRunnerFred 18.10.2014, 18:51
quelle

7 Antworten

4

Optimistisches Sperren bedeutet, dass mehrere Threads denselben Benutzerdatensatz bearbeiten können.

Was in Ihrer App passiert, ist, dass zwei (oder mehr) Änderungen an demselben Benutzereintrag vorgenommen werden und Ihre App dies korrekt erkennt und den entsprechenden Fehler anzeigt.

Was Sie normalerweise tun würden, ist der Fehler:

  • Sie könnten beispielsweise eine Nachricht wie "Leider wurde diese Änderung von jemand anderem bearbeitet, sodass Ihre Änderungen nicht gespeichert wurden" drucken.

  • Sie könnten beispielsweise eine beliebige Methode zum Abstimmen der Änderungen codieren, z. B. das Erkennen, dass eine Änderung den Namen der Person geändert hat, die andere Änderung die Telefonnummer der Person geändert hat und dann eine Möglichkeit zum Zusammenführen dieser Daten codieren zwei in eins speichern.

Im Allgemeinen können Sie auch user.reload verwenden, um eine neue Version des Benutzers abzurufen.

Ich schlage vor, Sie versuchen zuerst, optimistisches Sperren auszuschalten, während Sie Rails lernen. Optimistisches Locking ist eine großartige Optimierung für Geschwindigkeit, aber es sollte nicht benötigt werden, um eine typische Rails & amp; Devise App läuft erfolgreich.

Sie haben gefragt, was genau Devise tun könnte:

  • Wenn ein Benutzerdatensatz aktualisiert wird, aktualisiert das typische Rails ActiveRecord-Setup ein Tabellenfeld updated_at mit dem aktuellen Zeitstempel.

  • Ein typisches Setup von Modulen wie trackable aktualisiert den Benutzerdatensatz mit den neuesten Zeitangaben für das Anmelden und / oder Abmelden.

Eine einfache Möglichkeit zu beobachten, was passiert, ist das Feld lock_version :

  • Wenn Rails einen Datensatz lädt (z. B. ein Benutzer), erhöht Rails die Sperrversionsnummer.

  • Wenn Ihre App den Benutzer speichert, vergleicht Rails ActiveRecord die Nummer des Benutzerobjekts lock_version mit der Datenbank lock_version number.

  • Wenn die Zahlen übereinstimmen, ist das Speichern erfolgreich; Wenn die Nummer nicht übereinstimmt, löst Rails die veraltete Objektausnahme aus.

Beispielcode:

%Vor%

Devise und einige seiner verschiedenen Module fügen Felder zur Tabelle user hinzu. Dies ist schnell und bequem für typische Web-Apps, doch diese zusätzlichen Felder können Caching, Sperren, Persistenz, Serialisierung und dergleichen stören.

(Nebenbei sei angemerkt, dass Sie möglicherweise Devise im Vergleich zu anderen Sicherheitslösungen in Betracht ziehen. Eine besonders, die ich mag, heißt Sorcery; sie stellt ein Toolkit aus einer Handvoll Methoden zur Verfügung, die Sie so zusammenstellen können, wie Sie wollen Meine persönliche Erfahrung, Zauberei ist eine gute Möglichkeit, genau zu erfahren, was jeder Schritt in Ihrem eigenen Code macht, und Sie können das Zwischenspeichern und Sperren auf die von Ihnen gewünschte Weise steuern.)

    
joelparkerhenderson 22.10.2014 06:45
quelle
3

Ich habe ein ähnliches Problem gesehen. Der Fehler ist auf den Unterschied in der lock_version des Objekts zurückzuführen, das Sie zu aktualisieren versuchen. Sie können versuchen, das Objekt neu zu laden, bevor Sie das Update durchführen. Dies würde sicherstellen, dass das Objekt die neueste lock_version aufweist.

    
anosikeosifo 08.03.2016 15:10
quelle
1

Ich würde update_attribute in diesem Fall verwenden, da Sie Validierungen usw. nicht interessieren.

%Vor%

Ссылка

    
James Daniels 23.10.2014 20:41
quelle
1

Das gute Verhalten bei einer veralteten Objektausnahme hängt wirklich von Ihrer Anwendung ab.

Eine gute Lösung ist oft, den Job erneut zu versuchen:

%Vor%

Natürlich kann dies ein "falsches" Update irgendwo anders in Ihrem Code verbergen, aber es könnte Ihr Problem lösen, bis Sie das "falsche" Update gefunden haben

    
ThomasSevestre 27.10.2014 15:54
quelle
0

Es sieht so aus, als ob der Geräte-Session-Controller die Sitzung bereits zerstört hat, so dass Ihr aktueller Benutzer entweder zerstört oder zur Zerstörung markiert ist. Ich habe das Gerät eine Weile nicht benutzt, aber Sie sollten überprüfen, ob die Abfolge der Ereignisse in der Reihenfolge passiert, in der Sie denken, dass sie geschieht.

Versuchen Sie current_user.destroyed? in Ihrer before_logout-Methode. Es sieht so aus, dass before_logout für die Verarbeitung bestimmt ist, außer dass der current_user

manipuliert wird     
hraynaud 24.10.2014 06:12
quelle
0

Ich habe ein sehr einfaches Modul erstellt, um dies zu handhaben, wenn es möglich ist, neu zu laden, um das Problem zu beheben. Bitte beachten Sie, dass dies eine Race-Bedingung ist und Sie verantwortlich sind für das, was Sie für die db speichern.

%Vor%

Dann kannst du es einfach wie

verwenden %Vor%

Es wird versuchen, es 5 Mal standardmäßig zu tun, ein Neuladen wenn es fehlschlägt.

    
Arnold Roa 17.06.2017 13:22
quelle
0

Sie müssen einen Standardwert (0) für die Spalte lock_version in der Migrationsdatei

festlegen     
Deepak Sharma 05.12.2017 07:35
quelle