2012-08-22 11 views
6

Provo a creare un'applicazione a singola pagina con Rails 3.2 e Backbone.js con l'opzione pushState ma con qualcosa che non capisco.Come gestire gli URL non root in un'app a pagina singola?

Se carico l'URL di root dell'app (/), tutto va bene: Rails restituisce un layout HTML con JS che esegue il bootback di Backbone che rende alcuni XHR per entità JSON e rende il contenuto.

Ma se comincio usando app dalla URL non-root (ad esempio digitando manualmente nella barra degli indirizzi del browser) quindi Rails cercherà di gestire questa richiesta utilizzando il loro regole di routing da routes.rb - che è sbagliato, causa è una rotta "Backbone". Come posso caricare la pagina e il backstrap di bootstrap per gestire questo URL in quel caso?

risposta

14

Finalmente ho trovato la soluzione.

ho messo il seguente codice nel mio routes.rb

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

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

Con questo matcher tutte le richieste XHR non vengono indirizzati a HomeController che restituisce una pagina HTML. E le richieste XHR saranno gestite da altri controller che restituiscono le risposte JSON. Inoltre ho lasciato richieste che terminano con ".json" come valide nell'ambiente di sviluppo per il debug.

+0

Ottimo lavoro uomo! Questo dovrebbe essere aumentato di 1000 volte. – wuliwong

+0

Funziona perfettamente per me! – jordancooperman

+0

Ho trovato anche questo [ottimo articolo di artsy] (http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/) che descrive come creare un collegamento globale gestore con BackStone pushState per evitare l'aggiornamento della pagina, che ritengo sia molto in congiunzione con questa risposta e potrebbe aiutare alcune persone. – jordancooperman

1

Questo è un problema un po 'complicato, ma sostanzialmente in poche parole, è necessario rispondere a tutte le richieste (HTML) valide nei binari con la stessa pagina (radice), da lì il backbone prenderà il sopravvento e si dirigerà sulla rotta corretta gestore (nel tuo router bakckbone).

Ho discusso questo problema in modo più dettagliato qui: rails and backbone working together

Fondamentalmente quello che faccio è quello di creare azioni per ogni pagina che voglio gestire, e vista in bianco. Io uso respond_with per tornare alla pagina (che è la stessa in ogni caso) e perché mi occupo GET azioni solo per le richieste HTML, aggiungo questa linea nella parte superiore del controller:

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

richieste JSON sono gestito con respond_with, ma a differenza delle richieste HTML restituisce effettivamente la risorsa richiesta (ed esegue l'azione richiesta nel caso di PUT, POST e DELETE).

+0

Aggiornato la mia risposta con qualche informazione in più. –

+0

Questo farà il trucco ma non è troppo elegante in quanto tutte le rotte di Backbone devono essere responsabili da Rails. Quindi devi aggiornare i percorsi del server quando cambi le rotte del cliente.Non c'è davvero alcun modo per delegare tutte le richieste html al controller principale? – fey

+1

Non sono d'accordo: se si delegano * tutte * le richieste al controller principale, si sta dicendo che tutte le richieste sono valide, mentre in realtà la maggior parte non lo sono. Rails * ha bisogno * di sapere quali rotte sono valide e quali non sono al fine di restituire correttamente i codici di stato per percorsi errati, ecc. Questa è duplicazione ma è una duplicazione importante. È inevitabile una volta che inizi a utilizzare pushState. –

1

Backbone non verrà informato del tuo cambiamento di URL se lo fai manualmente. Questa modifica verrà presa dal browser e farà il suo lavoro inviando la richiesta al server come al solito.

Lo stesso se si fa clic su un normale collegamento , seguirà il suo href senza informare Backbone.

Se si desidera che il backbone si occupi di un cambio di URL, è necessario farlo tramite gli strumenti Backbone disponibili e questo è il proprio router.

Quindi, se si vuole fare una modifica URL nel modo Backbone bisogna farlo in modo esplicito, qualcosa come:

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