我有两种不同的模型可以显示在一个类别中。在我的 routes.rb 中,我希望有类似的内容:
ActionController::Routing::Routes.draw do |map|
map.top_list ':category/:foo', :controller => 'foo', :action => 'show'
map.top_list ':category/:bar', :controller => 'bar', :action => 'show'
end
当我加载像“/ some-category-name / some-foo-name”这样的URL时这很好用,其中“some-foo-name”可以由FooController加载,如下所示:
class FooController < ApplicationController
def show
@foo = Foo.find_by_url! params[:foo]
end
end
但是当我尝试请求一个Bar,比如“/ some-category-name / some-bar-name”时,我在FooController#show中得到一个“ActiveRecord :: RecordNotFound”。我知道我可以通过要求所有Foo名称以“foo-”开头并且所有Bar名称以“bar-”开头,然后定义如下路线来解决此问题:
ActionController::Routing::Routes.draw do |map|
map.top_list ':category/:foo', :controller => 'foo', :action => 'show', :requirements => { :name => /^foo-/ }
map.top_list ':category/:bar', :controller => 'bar', :action => 'show', :requirements => { :name => /^bar-/ }
end
但强制对名称进行这种限制是非常不理想的。我找到了以下内容,看起来可能对我有用:Different routes but using the same controller for model subclasses in Rails。但是,我不太关注这个例子,所以我不知道这是否能解决我的问题。我的Foo和BarController必须从CategoryController继承它也不是很好。
我想到的一个想法是,我可以尝试查找Foo,然后如果失败则回到BarController。我可以很容易地在FooController中执行此操作并重定向到BarController,但这不是很好,因为所有对Bars的请求都将在Rails日志中记录为FooController #show。但是,如果我能够以某种方式配置路由来调用方法来确定基于URL的基本名称路由到什么,我可以得到我需要的行为; e.g。
ActionController::Routing::Routes.draw do |map|
is_a_foo = Proc.new {|name| Foo.find_by_url! name && true }
map.top_list ':category/:foo', :controller => 'foo', :action => 'show', :requirements => { :name => is_a_foo }
map.top_list ':category/:bar', :controller => 'bar', :action => 'show'
end
在沼泽标准的Rails 2中有没有办法做到这一点?
答案 0 :(得分:2)
我最后写了一个小Rails插件,允许我写这样的路线:
map.with_options :category => /[-A-Za-z0-9]+/ do |m|
# Since both foos and bars can appear under category, we define a route for foo that only matches when
# the foo can be found in the database, then fall back to the bar route
m.foo ':category/:foo', :controller => 'foo', :action => 'show', :conditions => {
:url => { :find_by_url => Foo }
}
m.bar ':category/:bar', :controller => 'bar', :action => 'show'
end
在我获得开源代码的许可之前,我必须将实现作为练习留给读者,但这是我如何到达那里:
答案 1 :(得分:0)
这似乎是错误的,因为您使用相同的路由到两个控制器。只有你注意到,Rails才会选择一个。
使用这样的东西会更好:
map.top_list ':category/foo/:foo', :controller => 'foo', :action => 'show', :requirements => { :name => is_a_foo }
map.top_list ':category/bar/:bar', :controller => 'bar', :action => 'show'
因为在提供的路线中,每次都会给出两个参数。你用不同的名字命名并不重要。它只匹配两者。