2010-04-07 12 views
14

Me gustaría poder mapear URLs a Controladores de forma dinámica en función de la información en mi base de datos.URL dinámica -> Mapeo de controlador para rutas en Rails

que estoy buscando hacer algo funcionalmente equivalente a este (suponiendo un modelo View):

map.route '/:view_name', 
    :controller => lambda { View.find_by_name(params[:view_name]).controller } 

Otros han sugerido dynamically rebuilding the routes, pero esto no va a funcionar para mí, ya que puede haber miles de puntos de vista ese mapa al mismo controlador

+0

El controlador no necesita ser determinado por un registro de base de datos, solo quiero una forma de evaluar qué controlador usar para una ruta dada en Runtime, en lugar de Designtime. –

+0

Todavía nunca encontré una solución a esto, aunque parece una tarea simple. ¿Tal vez una aplicación en rack que vuelve a escribir las URL? –

Respuesta

0

Así que creo que usted está pidiendo que si usted tiene una mesa de Vistas y una vista de modelo para él, donde la mesa se ve como

id | name | model 
=================== 
1 | aaa | Post 
2 | bbb | Post 
3 | ccc | Comment 

¿Quieres una url de/aaa para apuntar a Post.controller - es esto correcto?

Si no, entonces lo que sugiere parece estar bien suponiendo que funciona.

Puede enviarlo a una acción catch all y hacer que la acción vea la url, ejecute find_by_name y luego llame al controlador correcto desde allí.

def catch_all 
    View.find_by_name('aaa').controller.action 
end 

actualización

Puede utilizar redirect_to e incluso enviar los parametros. En el ejemplo siguiente, te estoy enviando los parámetros de búsqueda

def catch_all 
    new_controller = View.find_by_name('aaa').controller 
    redirect_to :controller => new_controller, :action => :index, 
     :search => params[:search] 
end 
+0

¿Cómo se puede "llamar al controlador correcto"? Rails mantiene instancias de cada controlador y configura contextos de solicitudes, llena 'params', y muchas otras cosas, ¿cómo indico a los rieles que reenvíen la solicitud desde un controlador a otro? –

+0

Ver mi actualización anterior – Will

+0

redirect_to enviará una respuesta [302 HTTP] (http://en.wikipedia.org/wiki/HTTP_302) al cliente, haciendo que el navegador vuelva a solicitar la nueva URL. Esto no es lo que queremos. –

0

Aquí está una solución en rack de enrutamiento agradable para SEO aportado por Zetetic y Steve Ross

Testing Rack Routing Using rSpec

Se le muestra cómo escribir una costumbre despachador (donde puede hacer una búsqueda de base de datos si es necesario) y con restricciones y pruebas también.

0

Como se sugirió en la pregunta Rails routing to handle multiple domains on single application, supongo que podría usar Rails Routing - Advanced Constraints para construir lo que necesita.

Si tiene un espacio limitado de controladores (con vistas ilimitadas apuntando hacia ellos), esto debería funcionar. Simplemente cree una restricción para cada controlador que verifique si la vista actual los combina.

Asumiendo que tiene un espacio de 2 controladores (PostController y CommentController), se podría añadir lo siguiente a su routes.rb:

match "*path" => "post#show", :constraints => PostConstraint.new 
match "*path" => "comment#show", :constraints => CommentConstraint.new 

A continuación, cree lib/post_constraint.rb:

class PostConstraint  
    def matches?(request) 
    'post' == Rails.cache.fetch("/view_controller_map/#{request.params[:view_name]}") { View.find_by_name(request.params[:view_name]).controller } 
    end 
end 

Por último, cree lib/comment_constraint.rb:

class CommentConstraint  
    def matches?(request) 
    'comment' == Rails.cache.fetch("/view_controller_map/#{request.params[:view_name]}") { View.find_by_name(request.params[:view_name]).controller } 
    end 
end 

Usted puede hacer algo de improvisación como, por ejemplo, definir una clase de superconstricción que recupera el caché, por lo que no tiene que repetir el código y no corre el riesgo de obtener un nombre de clave de caché erróneo en una de las restricciones.

11

Esta pregunta es antigua, pero me pareció interesante.Se puede crear una solución totalmente funcional en Rails 3 usando la capacidad del enrutador para enrutar a un punto final de Rack.

Cree la siguiente clase de bastidor:

class MyRouter 
     def call(env) 
     # Matched from routes, you can access all matched parameters 
     view_name= env['action_dispatch.request.path_parameters'][:view_name] 

     # Compute these the way you like, possibly using view_name 
     controller= 'post' 
     my_action= 'show' 

     controller_class= (controller + '_controller').camelize.constantize 
     controller_class.action(my_action.to_sym).call(env) 
     end 
    end 

En Rutas

match '/:view_name', :to => MyRouter.new, :via => :get 

Indirecta recogieron en http://guides.rubyonrails.org/routing.html#routing-to-rack-applications que dice "Para los curiosos, 'índice de mensajes #' en realidad se expande a PostsController.action (: índice), que devuelve una aplicación de Rack válida ".

Una variante probada en Rails 3.2.13.

Cuestiones relacionadas