2017-12-28 12 views
2

ich Rails 5 um ein einfach rundenbasiertes Spiel Tracker für ein persönliches Gesellschaftsspiel mit (über Telefone/Tabletten/etc ..)Rails 5: Senden reload Kunden bei Datenaktualisierung setzen

Ich möchte alle "Spieler" im Spiel (Liste der Sitzungen/Benutzer/...) haben, um ihre Browser automatisch neu zu laden, sobald ein Spieler eine Aktion ausgeführt hat.

Ich weiß, dass es Live-Update-Funktionen wie AJAX und Websockets gibt, aber sie alle scheinen viel zu schwer für das, was ein einfaches Problem zu sein scheint. Außerdem möchte ich andere Clientseiten aktualisieren, nicht nur den Client, der die Aktion initiiert.

Gibt es eine einfache Lösung, um ein Reload zu senden? Oder muss ich etwas in einer der komplizierteren APIs programmieren?

+1

Die Verwendung von AJAX ist in diesem Fall am einfachsten.Allerdings ist das 'ActionCable' (WebSocket-Weg) in Rails 5 auch recht einfach zu implementieren. Wenn es möglich ist, sollten Sie es ausprobieren. – yeuem1vannam

+0

Gibt es ein einfaches Beispiel, das dies demonstriert? Alle AJAX-Tutorials, die ich angeschaut habe, verwenden AJAX, so dass die Aktionen eines Clients seine eigene Client-Seite aktualisieren können, ohne die gesamte Seite zu laden. Ich möchte Reloads an * andere * Clients senden. Ich werde die Frage aktualisieren, um dies klarer zu machen. –

Antwort

1

Für das einfache Problem können Sie immer noch AJAX verwenden, um Benutzerclient neu zu laden, indem Sie eine Intervallanforderung für jede XX Sekunden vornehmen. Der Server kann die letzte Aktionszeit zurückgeben, die für den Client verwendet werden kann, um festzustellen, ob er sich neu laden soll oder nicht.

Zum Beispiel auf dem Controller

# SomeController 
def get_last_action_time 
    # Return the timestamp of the last action 
    render json: {last_action_time: "2017-12-29 10:00:42 UTC"} 
end 

auf dem Client

function getLocalLastAction() { 
    /* return timestamp of the last action on local */ 
} 

function setLocalLastAction (time) { 
    /* Store the `time` to somewhere, ex: localStorage */ 
} 

function checkLastAction() { 
    $.getJSON("/get_last_action_time", function (data) { 
    if (getLocalLastAction() < data.last_action_time) { 
     /* destroy the interval */ 
     setLocalLastAction(data.last_action_time) 
     /* do the reload page */ 
    } else { 
     /* do nothing */ 
    } 
    }) 
} 

// Check every 1 second, shouldn't be too short due to performance 
var checking = setInterval(checkLastAction, 1000) 

Dann, wenn der Benutzer A eine Aktion zu tun, der Server last_action_time wird sich ändern, damit Client von anderen Benutzern wird bei neu geladen werden am meisten nach 1 Sekunde.

Dieser Weg ist alt, aber ziemlich einfach in einem einfachen Fall zu tun, und wenn Sie zusammen mit Aktionen Caching implementieren, ist die Leistung der App noch akzeptabel. In den komplizierteren Fällen Ich schlage vor, mit WebSocket Lösung für

  • Volle Kontrolle
  • Niedrige Latenz
  • Bessere Leistung für App
+0

Es scheint hier der einzige Vorteil gegenüber einem normalen Reload zu sein, dass die App nicht die ganze Seite neu laden muss? Ich nehme an, es bedeutet auch, dass die Benutzerseite nicht unter ihnen neu geladen wird ... –

+0

@DavidLjungMadison Nein, es bedeutet nicht, die ganze Seite neu zu laden oder nicht. Das Problem, das es löst, dass, wenn ein Benutzer A in LA bleibt und eine Aktion ausführt, Benutzer B bei CA die Seite automatisch nach weniger als 1 Sekunde neu lädt. Der AJAX hilft Ihnen nur zu überprüfen, ob jemand gerade etwas getan hat oder nicht und lädt dann die Seite bei Bedarf neu. – yeuem1vannam

+0

Richtig - ich meine, dass es Sie daran hindert, die Seite neu zu laden, aber der Client muss immer noch Daten vom Server abfragen/laden. In diesem Fall ist es die Aktionszeit anstelle der ganzen Seite, was eine Verbesserung darstellt. Es wäre schön, eine einfache Möglichkeit zu finden, Verbindungen zu jedem Client zu halten und das Reload vom Server direkt aufzurufen. –

0

Dank @ yeuem1vannam Antwort, hier ist die endgültige Code I verwendet, die hilft, den Race-Zustand einer Seite zu vermeiden, die alte Informationen lädt, während die Zeit aktualisiert wird und dann das Javascript, das die Zeit aktualisiert und die neue Zeit erhält, und folglich das Nachladen vermisst.

Der Javascript-Code:

var actionChecker; 

function doneChecking() { 
    clearInterval(actionChecker); 
} 

function checkLastAction() { 
    // Get the game ID from the html access span 
    var dataId = document.getElementById('javascript_data_access'); 
    if (!dataId) return doneChecking(); 
    var initActionTime = dataId.getAttribute('init_last_action_time'); 
    if (!initActionTime) return doneChecking(); 

    dataId = dataId.getAttribute('game_number'); 
    if (!dataId) return doneChecking(); 

    // Get the last action time 
    var ret = $.getJSON("/get_last_action_time/"+dataId, function (data) { 
    var lastActionTime = data.last_action_time; 
    if (!lastActionTime) return doneChecking(); 
    if (lastActionTime>initActionTime) { 
     location.reload(); 
    } 
    }) 
} 

window.onload = function() { 
    // Check every 1 second, shouldn't be too short due to performance 
    actionChecker = setInterval(checkLastAction, 1000); 
} 

Die Controller Aktion:

def get_last_action_time 
    last_time = nil 
    begin 
     @game = Game.find_by_id(params[:id]) 
     # Return the timestamp of the last action 
     last_time = (@game && [email protected]) ? @game.reloadTime.to_i : 0 
    rescue ActiveRecord::RecordNotFound 
     last_time = 0 
    end 
    # Stop bugging us after 30m, we should have moved on from this page 
    last_time==0 if (last_time!=0 && (milliseconds - last_time)>30*60*1000) 
    render json: {last_action_time: last_time} 
    end 

Und dann in der html.erb:

<span id='javascript_data_access' game_number=<%= params[:id] %> init_last_action_time=<%= @game.reloadTime %>></span> 

Natürlich müssen Sie reloadTime zu Ihrem Modell hinzufügen und auch endTime, wenn es eine Zeit gibt, in der Sie nicht mehr nach einem erneuten Laden suchen möchten.

Scheint zu funktionieren, bis jetzt, müssen Sie sicherstellen, dass Sie vorsichtig sind, wer verantwortlich für die Einstellung reloadTime ist. Wenn zwei Seiten reloadTime bei jedem Neuladen setzen, bleiben Sie in einem Reload-Loop-Kampf zwischen den beiden Seiten stecken.

Verwandte Themen