2010-04-07 19 views
14

Chciałbym móc dynamicznie mapować adresy URL do kontrolerów na podstawie informacji z mojej bazy danych.Dynamiczny adres URL -> Mapowanie kontrolera dla tras w Railsach

szukam coś zrobić funkcjonalnie równoważnego do tego (zakładając View modelu):

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

Inni sugerowali dynamically rebuilding the routes, ale to nie będzie działać dla mnie jak tam mogą być tysiące wyświetleń że mapa do tego samego kontrolera

+0

Sterownik nie musi być określony przez rekord bazy danych, chcę tylko w jakiś sposób ocenić, który kontroler ma być użyty dla danej trasy w Runtime, zamiast Designtime. –

+0

Nadal nigdy nie znalazłem rozwiązania tego problemu, chociaż wydaje się, że jest to proste zadanie. Może aplikacja typu rack, która ponownie zapisuje adresy URL? –

Odpowiedz

0

Więc myślę, że prosisz, że jeśli masz tabelę widoki i widoku modelu za to gdzie tabela wygląda

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

Chcesz, aby URL/aaa wskazywał na Post.controller - czy to prawda?

Jeśli nie, sugeruje się, że działa dobrze.

Możesz wysłać go do catch all action i sprawdzić akcję pod adresem URL, uruchomić find_by_name, a następnie wywołać odpowiedni kontroler.

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

Aktualizacja

Można użyć redirect_to a nawet wysłać params. W poniższym przykładzie was posyłam parametry wyszukiwania

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

W jaki sposób "wywołujesz właściwy kontroler"? Railsy zachowują instancje każdego kontrolera i konfigurują konteksty Requests, zapełniają 'params' i wiele innych rzeczy, w jaki sposób mogę instruować szyny, aby przekazywały żądanie z jednego kontrolera do drugiego? –

+0

Zobacz moją aktualizację powyżej – Will

+0

przekierowanie_do wysłania odpowiedzi [302 HTTP] (http://en.wikipedia.org/wiki/HTTP_302) do klienta, powodując, że przeglądarka ponownie zażąda nowego adresu URL. Nie tego chcemy. –

0

Tutaj jest miłym rozwiązaniem Rack Routing do SEO wniesione przez zetetic i Steve Ross

Testing Rack Routing Using rSpec

To pokazuje, jak napisać zwyczaj dispatcher (gdzie można wykonać wyszukiwanie db w razie potrzeby) oraz z ograniczeniami i testowaniem.

0

Zgodnie z sugestią na pytanie Rails routing to handle multiple domains on single application, można użyć Rails Routing - Advanced Constraints, aby zbudować to, czego potrzebujesz.

Jeśli masz ograniczoną przestrzeń kontrolerów (z nieograniczonymi widokami wskazującymi na nich), to powinno działać. Po prostu utworzymy ograniczenie dla każdego kontrolera, który sprawdza, czy bieżący widok je dopasowuje.

Zakładając, że przestrzeń 2 kontrolerami (PostController i CommentController), można dodać następujące wpisy do routes.rb:

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

Następnie utwórz 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 

Wreszcie utworzyć 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 

można zrobić kilka improv ementy, takie jak definiowanie klasy super-ograniczeń, która pobiera pamięć podręczną, więc nie musisz powtarzać kodu i nie ryzykujesz pobrania niewłaściwej nazwy klucza pamięci podręcznej w jednym z ograniczeń.

11

To pytanie jest stare, ale uznałem to za interesujące.W pełni funkcjonalne rozwiązanie można utworzyć w Rails 3, używając routera do kierowania do punktu końcowego Rack.

Utwórz następującą klasę Bagażnik:

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 

W Trasy

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

Podpowiedź odebrani z http://guides.rubyonrails.org/routing.html#routing-to-rack-applications który mówi „Dla ciekawskich posty Wskaźnik" faktycznie rozszerza się PostsController.action (: index), który zwraca prawidłową aplikację Rack. "

Wariant testowany w Railsach 3.2.13.

Powiązane problemy