Lets setzen Sie ein wenig Kontext zu dieser Frage. Eine E-Commerce-Anwendung in Ruby on Rails gegeben. Lassen Sie uns zum Beispiel 2 Modelle behandeln. Benutzer und Kreditkarte.ActiveRecord Update-Modell, während Rollback eine andere
Mein Benutzer ist im System nach einer Registrierung kein Problem dort. CreditCard ist ein Modell mit den Kreditkarteninformationen (ja, ich weiß über PCI-Compliance, aber das ist nicht der Punkt hier)
In der Kreditkarte Modell, ich schließe einen Rückruf nach_validation, die eine Überprüfung der Kreditkarte gegen Ihre Bank.
Lassen Sie mich hier einen einfachen Code eingeben.
models/user.rb
class User < ActiveRecord::Base
enum :status, [:active, :banned]
has_one :credit_card
end
models/credit_card.rb
class CreditCard < ActiveRecord::Base
belongs_to :user
after_validation :validate_at_bank
def validate_at_bank
result = Bank.validate(info) #using active_merchant by exemple
unless result.success
errors.add {credit_card: "Bank doesn't validate"}
user.banned!
end
end
end
Controller/credit_cards_controller.rb
class CreditCardsController < ApplicationController
def create
@credit_card = CreditCard.new(credit_card_params) # from Strong Parameters
if @credit_card.save
render #success
else
render #failure
end
end
end
Was verursacht mich Problem Es sieht aus wie Rails öffnet eine Transaktion in ActiveRecord, wenn ich ein neues mache. Zu diesem Zeitpunkt wird nichts an die Datenbank gesendet.
Wenn die Bank die Kreditkarte ablehnt, möchte ich den Benutzer verbieten. Ich mache das, indem ich verbotene Anrufe anrufe! Jetzt habe ich festgestellt, dass dieses Update zur selben Transaktion geht. Ich kann das Update sehen, aber sobald das Speichern nicht funktioniert, wird alles von beiden Modellen zurückgesetzt. Die Kreditkarte wird nicht gespeichert (das ist gut), der Benutzer wird nicht gespeichert (das ist nicht gut, da ich ihn verbannen möchte)
Ich versuche, einen Transaktionswrapper hinzuzufügen, aber das fügt nur einen Datenbankprüfpunkt hinzu. Ich könnte einen verzögerten Job für das Verbot schaffen, aber das scheint mir zu viel zu sein. Ich könnte einen Callback nach Rückruf verwenden, aber ich bin mir nicht sicher, ob das der richtige Weg ist. Ich bin ein wenig überrascht, ich habe dieses Szenario nie zuvor verstanden, was mich dazu gebracht hat zu glauben, dass mein Vater nicht korrekt ist oder der Punkt, an dem ich diesen Anruf mache, falsch ist.
Ok ich muss irgendwo schlecht vermasselt haben, weil ich das auf einem Seitenprojet nicht replizieren kann. Ich werde trotzdem nachforschen und zumindest die Lösung für dieses Problem veröffentlichen. – Hugues
Ok Die @ credit_card.save im Controller startet die Transaktion. Das ist in Ordnung und das macht Sinn. Nun, wenn ich mit dem Start der Transaktion user.update_column (info: "Not well") aufrufen möchte, wie mache ich das? – Hugues
Gefunden einige Informationen über die parallele Verarbeitung. http://stackoverflow.com/a/20743433/552443 Sie tun dies, indem Sie einen Thread starten und die Datenbank aus einem Verbindungspool erneut verbinden. Ich bin sicher, dass das funktioniert, aber ich finde diesen Overkill für ein einfaches Update eines Tisches. Hoffentlich bringt jemand eine Idee an den Tisch. – Hugues