2010-04-07 85 views
14

我希望能夠根據我的數據庫中的信息動態地將URL映射到控制器。動態URL - >控制器映射Rails中的路由

我在找做一些功能上等同於這個(假設View模型):

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

也有人建議dynamically rebuilding the routes,但是這不會爲我工作,因爲可能是成千上萬的意見映射到相同的控制器

+0

控制器不需要由數據庫記錄來確定,我只是想通過某種方式來評估在運行時爲給定路徑使用哪個控制器,而不是Designtime。 – 2010-04-09 18:13:21

+0

仍然沒有找到解決方案,儘管它看起來像一個簡單的任務。也許是重新編寫URL的機架應用程序? – 2011-01-16 23:20:36

回答

0

因此,我認爲你是問,如果你有一個意見表,併爲其視圖模型,其中表看起來像

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

你想要一個/ aaa的url指向Post.controller - 這是正確的嗎?

如果不是,那麼假設它工作,你的建議似乎很好。

您可以將它發送到捕獲所有操作並讓操作查看url,運行find_by_name,然後從那裏調用正確的控制器。

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

更新

您可以使用redirect_to時甚至發送PARAMS。在下面你的例子,我發送的搜索參數

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

你如何「調用正確的控制器」? Rails維護每個控制器的實例並設置Requests上下文,填充'params'和許多其他東西,我如何指示rails將請求從一個控制器轉發到另一個控制器? – 2010-04-08 03:52:35

+0

查看我的更新 – Will 2010-04-08 04:11:40

+0

redirect_to會向客戶端發送[302 HTTP](http://en.wikipedia.org/wiki/HTTP_302)響應,導致瀏覽器重新請求新的URL。這不是我們想要的。 – 2010-04-08 05:58:28

0

這裏是一個不錯的機架路由解決方案,搜索引擎優化貢獻的探究性和史蒂夫·羅斯

Testing Rack Routing Using rSpec

它展示瞭如何編寫自定義調度器(如果需要,可以在其中進行數據庫查找)和約束條件以及測試。

0

正如問題Rails routing to handle multiple domains on single application所示,我想你可以使用Rails Routing - Advanced Constraints來構建你所需要的東西。

如果您的控制器空間有限(無限的視圖指向他們),這應該起作用。只需爲每個控制器創建一個約束,以驗證當前視圖是否匹配它們。

假設你有2個控制器(PostController中和CommentController)的空間,你可以添加以下到您的routes.rb:

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

然後,創建的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 

最後,創建的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 

你可以做一些即興就像定義一個獲取緩存的超級約束類一樣,所以您不必重複代碼,也不會冒險在其中一個約束中獲取錯誤的緩存鍵名稱。

11

這個問題很舊,但我覺得它很有趣。Rails 3中可以使用路由器的能力路由到Rack端點來創建完整的工作解決方案。

創建以下機架類:

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 

在路線

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

提示從http://guides.rubyonrails.org/routing.html#routing-to-rack-applications它說「對於好奇, '帖子#指數' 回升實際上擴展出PostsController.action (:index),它返回一個有效的Rack應用程序。「

在Rails 3.2.13中測試的變體。