我希望能够根据数据库中的信息动态地将URL映射到控制器。
我希望做一些与此功能相同的事情(假设View
模型):
map.route '/:view_name',
:controller => lambda { View.find_by_name(params[:view_name]).controller }
其他人建议dynamically rebuilding the routes,但这对我不起作用,因为可能有数千个视图映射到同一个控制器
答案 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
您可以进行一些改进,例如定义一个获取缓存的超级约束类,这样您就不必重复代码,也不会冒险在其中一个约束中获取错误的缓存键名。