2011-08-02 12 views
15

Así que en los motores de Rails3 vienen con sus propios modelos/controladores/puntos de vista y de las rutas de los cursos. Ahora la pregunta es: ¿cómo se asegura que las rutas del motor se cargarán antes (o después) de las rutas de aplicación y todos los demás motores que estén presentes?rutas Control del orden de carga de los motores

He aquí un ejemplo de mis rutas de aplicaciones Rails:

match '*(path)', :to => 'foo_controller#bar_action' 

Y mi motor:

match '/news', :to => 'bar_controller#foo_action' 

Así por rutas predeterminadas Motores se cargará después de las aplicaciones. Esto significa que las rutas del motor son inaccesibles debido a esa ruta general en mi aplicación. ¿Cómo se pueden cargar las rutas del motor primero (o último)?

+0

¿Has probado mirar http://edgeguides.rubyonrails.org/configuring.html? Estoy bastante seguro de que puedes hacer lo que quieras usando ganchos e inicializadores –

+0

¿No es un duplicado de http://stackoverflow.com/questions/6310832/how-to-override-rails-app-routes-from-an- motor? –

+0

Por cierto, creo que las rutas de los motores siempre se cargan después de las rutas de la aplicación. –

Respuesta

28

Lo que estamos tratando de hacer es un poco difícil. Como se ha mencionado, las rutas del motor se cargan después de las rutas de la aplicación y anular este comportamiento puede ser problemático. Puedo pensar en varias cosas que puedes probar.

Usar un inicializador Después de enrutamiento Caminos inicializador

Hay un inicializador en engine.rb dentro de la fuente de rieles, una manera de lograr lo que busca es tratar de enganchar en la funcionalidad que se trata de. El inicializador tiene este aspecto por defecto:

initializer :add_routing_paths do |app| 
    paths.config.routes.to_a.each do |route| 
    app.routes_reloader.paths.unshift(route) if File.exists?(route) 
    end 
end 

Esencialmente, esto debe tomar las rutas de acceso a todos los archivos de rutas que Rieles conoce y tratar de agregarlos al recargador rutas (lo que reloades su archivo de rutas para que automaticamente si se cambia). Puede definir otra inicializador para ser ejecutados inmediatamente después de éste, a continuación, inspeccionar los caminos almacenados en el recargador rutas, saque el camino que pertenece a su motor, eliminarlo de la matriz caminos e inserte de nuevo, pero al final de la matriz de caminos. Así, en su config/application.rb:

class Application < Rails::Application 
    initializer :munge_routing_paths, :after => :add_routing_paths do |app| 
    engine_routes_path = app.routes_reloader.paths.select{|path| path =~ /<regex that matches path to my engine>/}.first 
    app.routes_reloader.paths.delete(engine_routes_path) 
    app.routes_reloader.paths << engine_routes_path 
    end 
end 

Esto puede o no puede trabajar, de cualquier manera que realmente no lo recomiendo, no es particularmente elegante (es decir feo truco jugar con las tripas de rieles).

Use rieles 3.1

esto puede no ser una opción, pero si lo es, probablemente me vaya con éste. En Rails 3.1 puede tener 2 tipos diferentes de motores, completos y montables (aquí está an SO question talking about some of the differences). Pero, en esencia, alterarías tu Motor para que sea un motor que se pueda montar, las rutas en un motor montable están en el espacio de nombres y puedes incluirlas explícitamente en el archivo de rutas de tu aplicación principal, p.:

Rails.application.routes.draw do 
    mount MyEngine::Engine => "/news" 
end 

También puede alcance sus rutas montado en el motor y hacer todo tipo de otras cosas de fantasía Routy (mas info) here. Para resumir, si puedes ir a 3.1 entonces este es el enfoque a usar.

insertar dinámicamente las rutas de su motor en su aplicación principal

Uno de los motores de Rieles más conocidos alrededor en este momento es inventar. Ahora, idear es un motor que potencialmente agregará un buen número de rutas a tu aplicación, pero si miras la fuente del diseño verás que en realidad no tiene un archivo config/routes.rb. Esto se debe a que el diseño agrega dinámicamente su bondad de enrutamiento al archivo de la aplicación principal routes.rb.

Al ejecutar el generador de modelo que viene con el legado, una de las cosas que el generador hacer es añadir una línea como devise_for :model en la parte superior de su archivo routes.rb, justo después de la línea Rails.application.routes.draw do. Por lo que su route.rb es similar a esto después de ejecutar un generador para crear un modelo de usuario:

Rails.application.routes.draw do 
    devise_for :users 
    ... 
end 

Ahora, devise_for es un método mágico que viene como parte del legado (en lib/devise/rails/routes.rb), pero en esencia lo hará cree un conjunto de rutas regulares que todos conocemos según el modelo que generó.

Lo que necesitamos saber es cómo insertar esta línea en el archivo de aplicaciones routes.rb, luego podemos escribir un generador en nuestro motor que insertará cualquiera de nuestras rutas en la parte superior del archivo de aplicaciones principales routes.rb. Para esto, miramos lib/generators/devise/devise_generator.rb. En el método add_devise_routes, la última línea es route devise_route. Route es una acción de Thor que inserta la secuencia que se le pasa al archivo de la aplicación principal routes.rb. Así podemos escribir un generador de nuestra propia y hacer algo similar ej .:

class MyCrazyGenerator < Rails::Generators::NamedBase 
    ... 
    def add_my_crazy_routes 
    my_route = "match '/news', :to => 'bar_controller#foo_action'" 
    route my_route 
    end 
end 

Por supuesto que se necesita para asegurarse de que toda la infraestructura del generador está en su lugar, pero esa es la esencia de la misma. Devise está escrito por algunos usuarios de rieles muy inteligentes y utilizado por un montón de gente, emular lo que hacen es probablemente una buena manera de hacerlo. De las 3 cosas que sugerí, esta sería la forma en que manejaría su problema (dado que cambiarse a los rieles 3.1 probablemente no sea una opción).

+0

Esto es genial. Gracias por su esfuerzo al responder esto. – Grocery

+0

Renuncié a mis sueños y utilicé el enfoque de diseño en lugar de parchear el código de enrutamiento real, al final es mucho más flexible, especialmente cuando estás envolviendo cosas en ámbitos personalizados. –

0

no soy un experto, pero yo estaba jugando con sferik/rails_admin ayer cuando me encontré con su solución de enrutamiento. Con su tarea rastrillo rails_admin:install, modifican directamente el archivo de config/routes.rb añadiendo mount RailsAdmin::Engine => '/admin', :as => 'rails_admin' en el principio del archivo para que estén seguros de que sus rutas siempre tienen la prioridad más alta. Eso mount método se refiere a su propia routes.rb:

RailsAdmin::Engine.routes.draw do 
    # Prefix route urls with "admin" and route names with "rails_admin_" 
    scope "history", :as => "history" do 
    controller "history" do 
     [...] 
    end 
    end 
end 

Podría ser esta la solución?

2

Teniendo el mismo problema en este momento. Otra solución no particularmente elegante pero segura que se me ocurre es agregar otra gema de motor al final de tu archivo gema, que solo contenga la ruta atrapar todo, nada más.

Editar: En realidad, counterintuitively, la gema de enrutamiento necesita ser enumerado antes todas las otras gemas de motor para sus rutas a ser cargados pasado.

+1

Sí. Básicamente se trata de mezclar gemas hasta que funcione la estrategia.Es infinitamente mejor para las gemas proporcionar un método que llamas explícitamente dentro de tus rutas.rb. De esa forma puedes controlar dónde quieres esas rutas (si es que las tienes). – Grocery

Cuestiones relacionadas