2012-08-22 8 views
6

Ich versuche, eine einzelne Seite App mit Rails 3.2 und Backbone.js mit Push-Option zu machen, aber mit etwas konfrontiert, das ich nicht verstehe.Wie behandelt man Nicht-Root-URLs in einer Einseiten-App?

Wenn ich die Root-URL der App (/) lade, geht alles recht: Rails gibt ein HTML-Layout mit JS zurück, welches Backbone bootstrappt, was einige XHRs für JSON-Entities macht und den Inhalt rendert.

Aber wenn ich mit App von Nicht-Root-URL starten (zB durch manuell in der Browser-Adressleiste eingeben), dann wird Rails versuchen, diese Anforderung mit ihren Routing-Regeln von routes.rb zu behandeln - das ist falsch, Ursache Es ist eine "Backbone" Route. Wie lade ich die Seite und den Bootstrap-Backbone für die Handhabung dieser URL in diesem Fall?

Antwort

14

Schließlich fand ich die Lösung.

Ich habe den folgenden Code in meine routes.rb

class XHRConstraint 
    def matches?(request) 
    !request.xhr? && !(request.url =~ /\.json$/ && ::Rails.env == 'development') 
    end 
end 

match '(*url)' => 'home#index', :constraints => XHRConstraint.new 

Mit diesem Matcher alle Nicht-XHR-Anfragen zu Homecontroller geleitet werden, die eine HTML-Seite zurückgibt. Und XHR-Anfragen werden von anderen Controllern bearbeitet, die JSON-Antworten zurückgeben. Auch Anfragen, die mit ".json" enden, wurden in der Entwicklungsumgebung zum Debuggen als gültig markiert.

+0

Gut gemacht Mann! Dies sollte 1000 Mal aktualisiert werden. – wuliwong

+0

Funktioniert perfekt für mich! – jordancooperman

+0

Ich fand auch, dass [großartige Artikel von artsy] (http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/) beschreibt, wie man einen globalen Link erstellt Handler mit Backbone pushState, um Seitenauffrischungen zu vermeiden, was meiner Meinung nach sehr viel mit dieser Antwort zusammenhängt und einigen Leuten helfen könnte. – jordancooperman

1

Dies ist ein etwas heikles Thema, aber im Grunde müssen Sie auf alle gültigen (HTML) Anfragen in Schienen mit der gleichen (Root) Seite reagieren, von dort wird das Backbone übernehmen und auf die richtige Route routen Handler (in Ihrem Bakckbone-Router).

Ich habe dieses Thema diskutiert hier im Detail: rails and backbone working together

Im Grunde, was ich tue, ist Aktionen für jede Seite zu erstellen, die ich, und leere Ansichten zu handhaben wollen. Ich benutze respond_with die Seite zurückzukehren (die gleich in jedem Fall ist) und weil ich nur für HTML-GET-Anfragen Aktionen behandeln, ich fügen Sie diese Zeile an der Spitze des Controllers:

respond_to :html, :only => [ :show, :new ] 

JSON-Anfragen sind auch mit respond_with behandelt, aber im Gegensatz zu den HTML-Anfragen tatsächlich die angeforderte Ressource zurückgeben (und die angeforderte Aktion im Fall von PUT, POST und DELETE ausführen).

+0

Aktualisiert meine Antwort mit ein bisschen mehr Info. –

+0

Das wird den Trick machen, aber es ist nicht zu elegant, weil alle Routen von Backbone von Rails verantwortlich sein müssen. Daher müssen Sie die Serverrouten aktualisieren, wenn Sie die Routen des Clients ändern.Gibt es wirklich keine Möglichkeit, alle HTML-Anfragen an den Root-Controller zu delegieren? – fey

+1

Ich stimme nicht zu: Wenn Sie * alle * Anfragen an den Root-Controller delegieren, dann sagen Sie, dass alle Anfragen gültig sind, obwohl die meisten nicht sind. Rails * muss * wissen, welche Routen gültig sind und welche nicht, um Status-Codes für falsche Routen usw. korrekt zurückgeben zu können. Dies ist eine Duplizierung, aber es ist wichtig, Duplikate. Es ist unvermeidlich, sobald Sie anfangen, pushState zu verwenden. –

1

Backbone wird nicht über Ihre URL-Änderung informiert, wenn Sie dies manuell tun. Diese Änderung wird vom Browser abgefangen und es wird seine Aufgabe erledigen, die Anfrage wie üblich an den Server zu senden.

Gleiches, wenn Sie in eine normale Verbindung klicken, folgt es seinem href ohne inform Backbone.

Wenn Backbone für eine URL-Änderung zuständig sein soll, müssen Sie dies über die Backbone-Tools tun, die Ihnen zur Verfügung stehen, und dies ist der eigene Router.

Also, wenn Sie eine URL Änderung der Backbone, wie Sie es explizit zu tun haben, machen, so etwas wie:

app.router.navigate("my/route", {trigger: true}); 
Verwandte Themen