2010-04-07 7 views
14

Ich möchte URLs zu Controllern dynamisch basierend auf Informationen in meiner Datenbank zuordnen können.Dynamische URL -> Controller-Zuordnung für Routen in Rails

Ich suche etwas funktional äquivalent zu dieser (unter der Annahme eines View Modell) zu tun:

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

Andere haben dynamically rebuilding the routes vorgeschlagen, aber das wird für mich nicht funktionieren, da es Tausende von Ansichten sein können dass auf demselben Controller-

+0

Der Controller muss nicht durch einen Datenbankeintrag bestimmt werden. Ich möchte nur einen Weg finden, um zu bestimmen, welcher Controller für eine bestimmte Route zur Laufzeit anstelle von Designtime verwendet werden soll. –

+0

Noch nie eine Lösung gefunden, obwohl es wie eine einfache Aufgabe scheint. Vielleicht eine Rack-Anwendung, die URLs neu schreibt? –

Antwort

0

So denke ich, dass Sie fordern, dass, wenn Sie eine Ansicht Tabelle und eine Ansicht Modell für sie, wo der Tisch wie

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

Sie möchten eine URL von/aaa auf Post.controller zeigen - ist das richtig?

Wenn nicht, dann scheint das, was Sie vorschlagen, in Ordnung, vorausgesetzt, es funktioniert.

Sie könnten es an alle Aktionen catch senden und die Aktion auf die URL schauen, führen Sie den find_by_name und rufen Sie dann den richtigen Controller von dort.

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

aktualisieren

Sie redirect_to verwenden können und sogar die params senden. Im Beispiel unten Sie mir die Parameter Suche

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

Wie "rufen Sie den richtigen Controller" an? Rails verwaltet Instanzen jedes Controllers und erstellt Requests-Kontexte, füllt Params und viele andere Dinge. Wie befehle ich Rails, die Anfrage von einem Controller zu einem anderen weiterzuleiten? –

+0

Siehe mein Update oben – Will

+0

redirect_to sendet eine [302 HTTP] (http://en.wikipedia.org/wiki/HTTP_302) Antwort an den Client, wodurch der Browser die neue URL erneut anfordert. Das ist nicht was wir wollen. –

0

Hier ist eine schöne Rack-Routing wird Lösung von zetetic und Steve ross trägt SEO

Testing Rack Routing Using rSpec

Es zeigt Sie schicke, wie ein benutzerdefinierte schreiben Dispatcher (wo Sie bei Bedarf eine Db-Suche durchführen können) und mit Einschränkungen und Testen.

0

Wie in der Frage Rails routing to handle multiple domains on single application vorgeschlagen, ich denke, Sie könnten Rails Routing - Advanced Constraints verwenden, um zu bauen, was Sie brauchen.

Wenn Sie einen begrenzten Bereich von Controllern haben (mit unbegrenzten Ansichten auf sie zeigen), sollte dies funktionieren. Erstellen Sie einfach eine Einschränkung für jeden Controller, der überprüft, ob die aktuelle Ansicht ihnen entspricht.

Vorausgesetzt, dass Sie einen Raum von 2 Controller haben (Postcontroller und Comment), könnten Sie Folgendes zu Ihrer routes.rb hinzufügen:

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

Dann erstellen 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 

Schließlich lib/comment_constraint.rb erstellen:

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 

Sie etwas Improvisations tun können B. das Definieren einer Super-Constraint-Klasse, die den Cache abruft, sodass Sie den Code nicht wiederholen müssen und nicht riskieren, einen falschen Cache-Schlüsselnamen in einem der Constraints abzurufen.

11

Diese Frage ist alt, aber ich fand es interessant.In Rails 3 kann eine voll funktionsfähige Lösung erstellt werden, die die Router-Funktionen zum Routen zu einem Rack-Endpunkt verwendet.

Erstellen Sie die folgende Rack-Klasse:

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 

In Routen

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

Hint up von http://guides.rubyonrails.org/routing.html#routing-to-rack-applications gepflückt, die „Für die Neugierigen, 'Beiträge # Index' erweitert tatsächlich heraus PostsController.action sagt (: index), die eine gültige Rack-Anwendung zurückgibt. "

Eine in Rails 3.2.13 getestete Variante.