2016-06-09 13 views
0

Nach einer anderen Frage (Rails controller - execute action only if the two methods inside succeed (mutually dependent methods)) möchte ich sicherstellen, dass innerhalb einer der Aktion meines Controllers, wenn der Benutzer die Nachricht nicht sehen Wenn sie von einer Rails UJS-Methode angezeigt werden, sind auch die ersten Methoden der Controller-Aktion nicht implementiert.Rails Controller - Aktion nur ausführen, wenn die Rails UJS-Methode erfolgreich ist (voneinander abhängige Methoden)

CONTEXT

Ich habe einen Regler mit einer Methode 'Aktionen' genannt. Wenn die App in die Methode 'example_action' eintritt, implementiert sie eine erste Methode (1) update_user_table und dann (2) eine weitere update_userdeal_table. (beide lesen und schreiben die Datenbank) und dann (3) eine dritte Methode, die sich auf einen Rails UJS (ajax) -Aufruf bezieht.

Mein Problem ist das folgende: Im Falle eines Timeouts in der Mitte des Controllers möchte ich vermeiden, dass die User-Tabelle (über Methode 1) aktualisiert wird, die UserDeal-Tabelle aber über Methode 2 aktualisiert wird NICHT die dritte Methode, dh die Ajax-Anfrage, die eine Meldung FAILS (Fehler, Timeout, ... Status wie 500 oder 404 oder abgebrochen oder Timeout ...) anzeigt.

In meiner App, für mobile Benutzer, wenn sie in einer U-Bahn mit Internetverbindung sind, starten sie die Anfrage, die durch 'example_action' Controller geht, führt erfolgreich die erste Methode (1) und zweite Methode (2) aber dann sie betreten einen Tunnel für 60 Sekunden mit sehr sehr niedriger (< 5b/sec) oder KEINE Internetverbindung, so dass ich aus UX-Gründen die Anfrage abbringe und dem Benutzer zeige, dass es zu lange gedauert hat, versuche es erneut. Das Problem ist, dass ich, wenn ich ihnen das Ergebnis (3) nicht zeigen konnte, nicht in der Lage sein muss, (1) und (2) auszuführen.

Ich brauche die beiden Methoden (1) und (2) und (3) "voneinander abhängig": Wenn einer nicht gelingt, sollte der andere nicht ausgeführt werden. Es ist der beste Weg, um es zu beschreiben.

Heute Hier ist mein Code. Es funktioniert nicht, da ich manuell durch Klicken versuche und dann nach nur 2 Sekunden die Internetverbindung abbringe. Ich sehe in meiner Datenbank, dass (1) und (2) ausgeführt wurden und die Datenbanken aktualisiert wurden, aber ich sah die Meldung "Entschuldigung, es hat zu lange gedauert, versuche es erneut".

Ist das der richtige Ansatz? Wenn ja, wie? Wenn nicht, sollte ich einen anderen Winkel versuchen wie: Wenn (1) und (2) erfolgreich waren, aber nicht (3) sollte ich die Tatsache speichern, dass die Schienen UJS xhr Status ein Fehler oder Timeout war, dass folglich das modale wxas nicht effektiv dem Benutzer angezeigt werden und ihnen dann das Ergebnis/die Nachricht zeigen, sobald sie wieder online sind? Hier

ist der Code

HTML-Seite für den Benutzer der Benutzer klicken Sie auf eine Schaltfläche, die eine Rails UJS Aajax Anfrage auslöst, die letztlich die modale Meldung angezeigt wird

<div id=zone"> 
    <%= link_to image_tag(smallest_src_request), 
      deal_modal_path, 
      remote: true %> 
</div> 

Dies senden eine Route, die auf diese Controller-Aktion zeigt

Deal-Controller

class DealsController < ApplicationController 
    def deal_modal 
    Deal.transaction do 
     update_user_table # that's the (1) 
     update_userdeal_table # that's the (2) 
     # show_modal_message 
     respond_to do |format| 
     format.js 
     end 
    end 

    private 
    def update_user_table 
    # update the table User so it needs to connect to internet and acces the distant User table 
    end 
    def update_userdeal_table 
    # update the table UserDeal table so it needs to connect to internet and access the distant UserDeal table 
    end 
end 

Dies deutet auf eine js.erb Ansicht Datei

deal_modal.js.erb

showModalMessage("Here is your result <variable and all>); 

die Ajax, Fehler zu verwalten, Timeouts ... (wenn auf die Auflösung der Frage erforderlich), verwende ich Rails UJS Einstellungen.

WICHTIG: Es ist hier, dass ich im Falle eines Fehlers oder Timeouts die modale Meldung "error/timeout" an die Stelle der sonst üblichen senden (siehe oben "Hier ist Ihr Ergebnis ..")

$(document).on('page:change', function() { 
     $("#zone"). 
     on('ajax:error',function(event,xhr, status, error){ 
      console.log(' ajax call failed:', error); 
      var msg; 
      msg = Messenger().post({ 
      hideAfter: 4, 
      message: "sorry it took too long, try again." 
      }); 
    }); 

$(document).on('page:change', function() { 
    //set timeout Rails UJS ajax option that will display message for ajax:error cases defined above 
    $.rails.ajax = function(options) { 
    if (!options.timeout) { 
     options.timeout = 5000; 
    }  
    return $.ajax(options); 
    }; 
}); 

Antwort

1

So wird die Transaktion nur Rollback, wenn ein Fehler ausgelöst wird. Wenn ein unbehandelter Fehler ausgelöst wird, stürzt Ihre Anwendung ab und es wird auf irgendeine Weise ein Fehler von 500 angezeigt.

Um die Antwort auf den Benutzer bei Erfolg oder Fehler anzuzeigen, müssen Sie etwas rendern. Sie wollen also nicht verhindern, dass der respond_to-Block ausgeführt wird. Eine Möglichkeit, dies zu umgehen, wäre das Setzen eines Flags über eine Instanzvariable.

def deal_modal 
    begin 
    Deal.transaction do 
     update_user_table 
     update_userdeal_table 
    end 
    @success = true 
    rescue 
    @success = false 
    end 
    # show_modal_message 
    respond_to do |format| 
    format.js 
    end 
end 

Dann in deal_modal.js.erb

<% if @success %> 
    showModalMessage("Here is your result <variable and all>"); 
<% else %> 
    showModalMessage("There was a problem"); 
<% end %> 

EDIT:

mit Verbindungsproblemen Der Umgang ist auf jeden Fall kompliziert und es ist nicht wirklich eine ideale Lösung. Ich lasse die Datenbank im Allgemeinen ununterbrochen laufen und lasse sie entweder einen Erfolg oder einen Fehler zu ihrer eigenen Zeit zurückgeben. Für langwierige Transaktionen können Sie einen Edelstein wie delayed_job oder sidekiq verwenden, um die Aktion im Hintergrund zu verarbeiten und den Rails-Controller eine Antwort mit der Antwort "... pending ..." oder etwas zurückgeben zu lassen. Sofern Sie keine Websockets im Frontend verwenden, bedeutet dies, dass Sie den Server ständig mit Ajax-Anfragen abfragen, um zu sehen, ob der Hintergrundprozess abgeschlossen ist.

+0

Ich werde versuchen, aber ich frage mich, ob Transaktionen "verwendet werden"/kann tatsächlich einen "nicht Ruby" Fehler fangen. Dh wenn das Rails UJS einen Fehler wie Status 'timeout' oder 'error' (was nicht wirklich ruby-ocosystem sondern eher eine JavaScript-Sache ist) auslöst, wird die Transaktion es als Fehler klassifizieren und zum Block rescue @ success = false wechseln ? – Mathieu

+0

Ich denke, was Sie vorschlagen, ist cool, aber erfüllt meine Frage nicht oder ich könnte Ihren Vorschlag missverstehen: mein Ziel ist, dass wenn die Rails UJS (via Antwort_to Format.js) Timeouts, dann die beiden ersten Methoden update_user_table und _updateuserdeal_table zurückgerollt werden. In gewissem Sinne ist es wie bei der vorherigen Frage: Ich möchte, dass diese 3 Methoden "zusammenkommen": Wenn der dritte fehlschlägt, dann möchte ich nicht, dass die 2 zuerst ausgeführt wird (oder zumindest möchte ich, dass sie zurückgesetzt werden) – Mathieu

+0

Mein aktueller Code bereits ermöglichen mir, ihnen die Fehlermeldung zu zeigen ("Entschuldigung zu lange, versuche es erneut", wenn es Timeout: das funktioniert bereits. Was nicht funktioniert ist, dass, selbst wenn es ihnen die Rails UJS Fehlermeldung angezeigt wird. .. '), update_user und update_userdeal werden nicht zurückgesetzt und die Updates auf der Datenbank werden nicht "abgebrochen" – Mathieu