动态网址 - > Rails中路由的控制器映射

时间:2010-04-07 22:14:52

标签: ruby-on-rails model-view-controller url-routing

我希望能够根据数据库中的信息动态地将URL映射到控制器。

我希望做一些与此功能相同的事情(假设View模型):

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

其他人建议dynamically rebuilding the routes,但这对我不起作用,因为可能有数千个视图映射到同一个控制器

4 个答案:

答案 0 :(得分:13)

这个问题很老,但我发现它很有趣。可以使用路由器路由到机架端点的功能在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中提到“为了好奇,'posts #index'实际上扩展为PostsController.action(:index),它返回一个有效的Rack应用程序。”

在Rails 3.2.13中测试的变体。

答案 1 :(得分:0)

所以我认为你问的是,如果你有一个Views表和一个View模型,那么表格就像

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

你想要一个/ aaa的url指向Post.controller - 这是对的吗?

如果没有那么你的建议似乎很好,假设它有效。

您可以将其发送到catch all操作并让操作查看url,运行find_by_name然后从那里调用正确的控制器。

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

更新

您可以使用redirect_to甚至发送参数。在下面的示例中,您将发送搜索参数

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

答案 2 :(得分:0)

这是由zetetic和Steve ross提供的一个很好的SEO路由解决方案

Testing Rack Routing Using rSpec

它向您展示了如何编写自定义调度程序(如果需要,您可以在其中执行数据库查找)以及约束和测试。

答案 3 :(得分: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

您可以进行一些改进,例如定义一个获取缓存的超级约束类,这样您就不必重复代码,也不会冒险在其中一个约束中获取错误的缓存键名。