203: Routing in Rails 3
(From asciicasts.com and Railscast )
Translated by Yinghai. Please contact zyinghai at gmail.com regarding this translation.
翻译的比较急,如有问题,请联系zyinghai at gmail.com
这一集我们继续研究Rails的新特性, 这次我们看一下Rails 3的路由. Rails 3提供了一些新的API和新的功能来定义路由. 为了更好的演示,我们先建立一个detour应用。
建立好应用之后,我们可以打开config/routes.rb文件看一下. 默认的文件包含了一些演示新API的文档和例子,当你有空的时候,这些都值得一看。 我们先删掉自带的文档,换上老的格式,再来对比一下Rails 3新的用法。
/config/routes.rb
map.resources :products, :member => { :detailed => :get }
map.resources :forums, :collection => { :sortable => :get, :sort => :put } do |forums|
forums.resources :topics
end
map.root :controller => "home", :action => "index"
map.about "/about", :controller => "info", :action => "about"
end
以上是需要转化的老格式。
我们先从这一个开始:
这个路由有一个product资源,和一个叫做detailed的附加action,可以通过Get方法请求。
Rails 3第一个值得注意的改变,就是我们不再使用map对象,取而代之的是在routes.draw块里面直接调用resources。resources包括的:member和:collection 动作,可以通过一个块来定义, 上述的路由可以新格式是这样:
get :detailed, :on => :member
end
下面,我们来看以下更复杂的路由:
forums.resources :topics
end
这个路由,在forum资源里面,我们有两个额外的:collection动作,还有一个嵌套的Topic资源。新的API中,可以写成这样:
collection do
get :sortable
put :sort
end
resources :topics
end
以上代码在一次展示了取消map.resources,直接用resources块。我们有两个collection动作,尽管我们可以像第一个例子中detailed动作一样使用:on,但我们这里用collection块达到了同样的效果 (member动作也可以使用member块)。任何在这个块里面定义的路由,都会作用在forums的集合上。在我们的例子中,我们定义了两个,一个是GET方法的sortable和PUT方法的sort。
至于嵌套的topics资源,我们可以在forums的块里再次调用resources,起到嵌套的效果。
下一个路由,我们看一下怎么定义root的控制器和动作。
这里,我们可以直接调用root,用:to来定义要转到的动作,控制器跟动作之间,可以用#来区隔。
用一个#分隔的字符串来定义控制器跟动作,是Rails 3的新特性之一。我们可以用类似的格式来定义named路由。
Rails 3中改写成这样:
没有:as参数,这个路由就是单纯的转向”/about”, 加了:as 之后,在我们的应用里面可以使用about_path或者about_url。
新功能
从上面的例子可以看出,只需要微小的改动,就可以从老的API转化到新的API,但是真正吸引人的是新API提供的一些新功能,下面我们来看其中的一部分。
可选参数
前一个版本就已经有对可选参数的支持,但是用法比较麻烦,下面我们来看一下Rails 3中怎么使用。
我们建立一个info控制器和about动作来展示可选参数。Rails 3支持用rails g来作为rails generate的快捷方式。
我们可以用rails s快捷方式来启动服务器
现在我们打开http://localhost:3000/about, 我们会转到之前已经在路由配制文件里面定义的info#about动作。

假设我们下一步想要添加对pdf格式的支持,可是现在打开http://localhost:3000/about.pdf的话,我们会看到一个路由错误,提示没有定义路由。
在路由文件里,我们可以添加一个format参数。
如果我们刷新页面,这次会得到应用找不到template错误。

我们已经解决了之前的问题,但是format参数不是可选参数,如果我们返回之前没有.pdf后缀的页面,我们会遇到路由错误,我们可以做简单的改动,只需用括号括起来,就可以让format变为可选参数。
然后我们可以正常的打开http://localhost:3000/about 或者 http://localhost:3000/about.pdf。
下面,我们来看一下怎么使用更为复杂的可选参数,例如,我们现在有一个博客应用,我们想要在网址中,用可选的年月日来过滤一段特定时间的贴子。
我们可以用下面的路由达到这个效果,主义括号可以嵌套起来定义多个可选参数。
在view中,我们添加一些调试信息,来检查传入的参数:
/app/views/info/about.html.erb
下面,如果我们传入year参数,about动作会收到我们传入的值,month和day参数也是如此。

这个路由是比较宽泛的,如果我们传入,例如http://localhost:3000/foo/bar,这样的参数也会被传到控制器,很显然,想要符合日期规范的参数,我们可以用constrains来达到这样的目的。
Constraints
Constraints 就是Rails 2中的requirements. :constraints可以传入一个hash来限定匹配。以下的例子用四个数字来限定年,两个数字来限定月和日。
添加了这个constraint之后,我们再看一下/foo/bar路径,这次我们得到了一个无法匹配的错误。

我们现在做的,Rails 2的requirements都可以做到。但是Rails 3的Constraint更加强大。
例如,我们可以用user_agent参数来限制一些浏览器的访问,以Firefox为例。
如果我们用Safari, Chrome或者Opera访问页面,我们会看到一个匹配错误。但是Firefox可以正常浏览。

我们也可以添加一些更有用处的constraint比如主机名。
使用这个constraint,我们可以通过http://localhost:3000/secret来浏览网页,但是用ip地址将会返回错误( http://127.0.0.1/secret ),其实两个地址本质上都是一样的。这个功能可以用来限制某些二级域名的访问,目前这一部分还在开发中,在以后的版本中,constraint可以传入:subdomain参数。
如果我们有多个路由同时使用一个constraint,会造成很多代码的重复。我们可以用constraints方法把这些路由放到一个块中来降低代码重复。
match "/secret" =>; "info#about"
match "/topsecret" => "info#about"
end
还有很多constraint的高级功能,就不在这里一一赘述了。
Rack路由
因为时间的关系,我们没办法涵盖所有Rails3的路由改进,我们会在未来的视频里慢慢接触。 我今天想介绍的最后一个功能,是Rails 3路由与Rack的集成。
通常我们将地址匹配到一个控制器和动作,但是我们也可以匹配给一个Rack应用,这是一个非常强大的功能,我用一个简单的Rack应用来展示这个功能。
如果你不是很熟悉Rack,可以看一下第151集视频,我们上面代码就是返回HTTP成功代码,和很简单的内容。
我们访问 /hello 就可以看到“Hello Rack!,以此我们可以看出Rack工作正常并响应请求.你可以用这个强大的功能将路由转到不同的应用。比如可以将路由匹配到Sinatra应用。

Rails 3的路由功能带来了很多令人振奋的可能性,尽管今天我们只是大体地介绍了一下,以后我们会详细的介绍一些具体用法。
如果你需要更多Rails 3的路由信息,可以参考Yehuda Katz的博客和RailsGuides.
Please contact zyinghai at gmail.com regarding this translation.
翻译的比较急,如有问题,请联系zyinghai at gmail.com
{ 5 } Comments
I hope you will write more articles better.
很多已经翻译了,中文的文章在这里http://cn.asciicasts.com/episodes, 你有特别想要了解的么,关于Rails 3的,或者其他的,可以给我说
您好,感谢您能给我回复:)
正在按照cn.asciicasts.com里的Rails新特性在学习,收获很多。
只是,我有时候总是纠结于Rails,Ruby,Server,Database… …的版本升级或搭配,而没能将精力全部集中在编写核心程序上。
昨天晚上(北京时间),我还升级到了最新的Rails Third beta。
安装了RVM,安装了一个稳定版本的Ruby和另一个版本Ruby-1.9.2-head,基于后一个Ruby版本安装Rails 3 来学习新的特性。
1. Ruby-1.8.7 + Rails-3 + Postgresql + Passenger-Nginx
2. Ruby-1.9.2-head + Rails-3 + Postgresql + Passenger-Nginx
– “您对于在搭配方面有什么建议么?”
(我似乎又纠结于性能了,而没能集中精力编程)
– “像我这样的症状(没能集中精力编程)有解么?”
感谢您的帮助!
Sha Jun
我觉得,性能问题得等到出现的时候,根据具体情况找一个具体解决方案。
你给出的两个配置,我觉得在开发的机器上,性能区别可能不大。
部署的话,我还是倾向稍微稳定一些的,不然好多问题自己研究也挺耗时间的。
:)感谢您给的建议!
在稳定的环境中集中精力编写程序,不折腾了,等release candidate后再说吧!
会关注您的博客以及您在cn.asciicasts.com发布的文章。
Sha Jun
Ruby.JSha@gmail.com
Post a Comment