2016-04-27 5 views
0

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.

+0

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

+0

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

+0

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

Antwort

0

Nach viel Kritik und mehr Graben habe ich 3 Möglichkeiten gefunden, mit dieser Situation umzugehen. Je nach den Bedürfnissen, die Sie haben, sollte einer von ihnen gut für Sie sein.

  1. separaten Thread und neue Datenbankverbindung
  2. die Funktion Validate aufrufen, bevor der explictly speichern
  3. die Aufgabe an einen Delayed Job

    • separaten Thread
    führen zu

    Die folgende Antwort zeigt, wie th zu tun ist ist die Operation.

https://stackoverflow.com/a/20743433/552443

Dies funktioniert, aber wieder nicht so schön und einfach.

  • Anruf gültig? vor dem Speichern

Dies ist eine sehr schnelle Lösung. Das Problem ist, dass ein neuer Entwickler das gültige löschen könnte? Linie denken, dass die .save die Arbeit richtig machen wird.

  • Sprech Job Verzögerte

Dieser jeder ActionJob Anbieter sein könnte. Sie können die Aufgabe senden, um den Benutzer in einem separaten Thread zu sperren. Je nach Setup ist das ziemlich sauber, aber nicht jeder braucht DelayedJob.

Wenn Sie etwas sehen, fügen Sie es bitte zu einer neuen Lösung der Kommentare hinzu.

Verwandte Themen