2010-04-07 88 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中测试的变体。