2012-08-22 9 views
6

Intento hacer una aplicación de una sola página con Rails 3.2 y Backbone.js con la opción pushState pero con algo que no entiendo.¿Cómo se manejan las URL no root en una aplicación de una sola página?

Si cargo la URL raíz de la aplicación (/), todo va bien: Rails devuelve un diseño HTML con JS que inicia el Backbone que hace algunos XHR para entidades JSON y representa el contenido.

Pero si empiezo a usar aplicación de URL no root (por ejemplo, escribir manualmente en la barra de direcciones del navegador) y luego rieles tratarán de manejar esta solicitud utilizando el suyo reglas de enrutamiento de routes.rb - eso está mal, causa es una ruta de "Backbone". ¿Cómo cargo la página y el Backbone de arranque para manejar esta URL en ese caso?

Respuesta

14

fin encontré la solución.

pongo el siguiente código en mi 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 esta matcher todas las peticiones XHR no se enrutan a HomeController que devuelve una página HTML. Y las solicitudes XHR serán manejadas por otros controladores que devuelven respuestas JSON. También dejé las solicitudes que terminan en ".json" como válidas en el entorno de desarrollo para la depuración.

+0

Great job ¡hombre! Esto debe ser votado 1000 veces. – wuliwong

+0

¡Funciona perfectamente para mí! – jordancooperman

+0

También encontré este [gran artículo escrito por artsy] (http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/) que describe cómo crear un enlace global controlador con Backbone pushState para evitar actualizaciones de página, lo cual creo que está muy relacionado con esta respuesta y podría ayudar a algunas personas. – jordancooperman

1

Esto es un problema un poco complicado, pero básicamente en pocas palabras, debe responder a todas las solicitudes válidas (HTML) en raíles con la misma página (raíz), a partir de ahí la red troncal tomará el control y la ruta correcta controlador (en tu enrutador bakckbone).

he discutido este tema con más detalle aquí: rails and backbone working together

Básicamente lo que hago es crear acciones para cada página que quiero manejar, y vistas en blanco. Yo uso respond_with para volver la página (que es la misma en cada caso) y debido a que manejo CONSIGO acciones única para las solicitudes de HTML, agrego esta línea en la parte superior del controlador:

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

peticiones JSON son manejado con respond_with también, pero a diferencia de las solicitudes HTML realmente devuelve el recurso solicitado (y realiza la acción solicitada en el caso de PUT, POST y DELETE).

+0

Actualicé mi respuesta con un poco más de información. –

+0

Eso hará el truco, pero no es demasiado elegante porque todas las rutas de Backbone deben ser responsabilidad de Rails. Por lo tanto, debe actualizar las rutas del servidor cuando cambie las rutas del cliente.¿Realmente no hay forma de delegar todas las solicitudes html al controlador raíz? – fey

+1

No estoy de acuerdo: si delega * todas las solicitudes al controlador raíz, entonces está diciendo que todas las solicitudes son válidas, cuando en realidad la mayoría no. Rails * necesita * saber qué rutas son válidas y cuáles no para devolver correctamente los códigos de estado para rutas incorrectas, etc. Esta es una duplicación pero es una duplicación importante. Es inevitable una vez que empiezas a usar pushState. –

1

Backbone no será informado de su cambio de URL si lo hace manualmente. Este cambio será capturado por el navegador y hará su trabajo enviando la solicitud al servidor como de costumbre.

Lo mismo si hace clic en un enlace normal , seguirá su href sin informar Backbone.

Si desea que Backbone se haga cargo de un cambio de URL, tiene que hacerlo a través de las herramientas de Backbone que tiene disponibles y este es el enrutador propio.

Así que si usted desea hacer un cambio de dirección URL en la forma en la espina dorsal que tiene que hacer de forma explícita, algo así como:

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