通过上一讲,我们已经对REST on Rails的基本框架有所了解,但是它是如何实现根据客户端的请求类型来返回不同类型的资源表示的呢?这就是我们这一讲所要讲的,秘密就在于respond_to。
首先让我们来看看我们在上一讲中生成的airports控制器的代码:
class AirportsController < ApplicationController
def index
@airports = Airport.find :all
respond_to do |format|
format.html # do nothing, allow Rails to render index.rhtml
format.js # do nothing, allow Rails to render index.rjs
format.xml { renderml => @airports.to_xml }
end
end
end
我们以index方法为例,其它方法的实现大同小异。第一行代码很容易理解,获取所有的机场信息,但是接下来的代码就比较费解了,而这也正是REST on Rails的关键所在,那个respond_to是做什么的呢?
我们知道,在HTTP协议中,客户端会在他们的HTTP首部包含一些元信息(meta-information),这些元信息按照“字段:值”的方式来组 织,HTTP协议预定义了很多标准字段,其中的一个字段就是“Accept-type“,它代表发送请求的客户端能够支持或者说理解的资源表示类型,如果 没有为这个键指定值,服务端会认为客户端能够理解标准的HTML文档,当然,客户端可以为这个字段指定任意的符合MIME规范的类型值,假设客户端设置这 个字段为”Accept-Type: text/xml“,则服务端必须返回资源的XML表示。
所以respond_to事实上就是根据HTTP首部的Accept-Type字段来决定向客户端返回那种类型的资源表示,如果不使用respond_to,我们的实现可能会是这个样子:
class AirportsController < ApplicationController
# Pretend that Rails will call our index action,
# and will pass in the value of the Accept-Type header
def index(client_format)
@airports = Airport.find :all
if client_format == “text/html”
# TO DO: render the default template
elsif client_format == “application/javascript”
# TO DO: return some javascript
elsif client_format == “application/xml” || client_format == “text/xml”
# TO DO: return some XML back the client
# … more elsif statements here for each MIME type you want to support
end
end
end
这很丑陋,不是吗?但它却相当直观,我想respond_to的作者可能最初也是这么写的,或者这段代码至少在他的脑海中闪现过,但立刻就被他否定了,因为它实在是太蹩脚了,所以他对这段代码进行了重整,于是有了respond_to。
respond_to do |format|
format.html # do nothing, allow Rails to render index.rhtml
format.js # do nothing, allow Rails to render index.rjs
format.xml { renderml => @airports.to_xml } #转换格式
end
但是Block内的代码看起来仍然比较古怪,事实上,如果我们理解了respond_to的设计思想,那么这段代码看起来就非常理所当然了。
respond_to基于这样的思想设计的,你不需要知道客户端的请求到底是那种类型,你只需要告诉Rails你准备支持那些类型的请求,Rails会自动帮你处理剩下的事情。
所以,这里我们告诉Rails,对于HTML和JS类型的请求,采用默认的实现,而对XML则使用我们在Block内提供的实现。
指南到这里就结束了,篇幅有限,我们只能对REST的基本概念和它在Rails中的简单实现做一个基本的介 绍,REST on Rails的世界还有更多的东西等着你去探索。
我建议你尝试动手创建一个Rails应用,然后试试scaffold_resource生成器,阅读并试着理解生成的代码,然后尝试修改view和controller,事实上,比你想象的要简单的多,不是吗?
此外,关于response to? 与send的用法,可参考http://selfcontroller.iteye.com/blog/1139556
如同其他的OO语言一样,在ruby中,通过给对象发送消息,来完成对象的功能,比如 str.upcase ,就是给str发送upcase的消息,点操作符(.),就是用来给对象发送消息的,str接受到消息,然后执行与消息对应的功能。
与 respond_to? 相对应,send 方法和点操作符一样,用来给对象发送消息。且send 发送的消息,在程序运行时是可变的,我们可以根据不同的输入,动态的向对象发送不同的消息。
首先让我们来看看我们在上一讲中生成的airports控制器的代码:
class AirportsController < ApplicationController
end
class AirportsController < ApplicationController
# Pretend that Rails will call our index action,
if client_format == “text/html”
elsif client_format == “application/javascript”
elsif client_format == “application/xml” || client_format == “text/xml”
# … more elsif statements here for each MIME type you want to support
end
这很丑陋,不是吗?但它却相当直观,我想respond_to的作者可能最初也是这么写的,或者这段代码至少在他的脑海中闪现过,但立刻就被他否定了,因为它实在是太蹩脚了,所以他对这段代码进行了重整,于是有了respond_to。
respond_to do |format|
end
respond_to基于这样的思想设计的,你不需要知道客户端的请求到底是那种类型,你只需要告诉Rails你准备支持那些类型的请求,Rails会自动帮你处理剩下的事情。
我建议你尝试动手创建一个Rails应用,然后试试scaffold_resource生成器,阅读并试着理解生成的代码,然后尝试修改view和controller,事实上,比你想象的要简单的多,不是吗?
此外,关于response to? 与send的用法,可参考http://selfcontroller.iteye.com/blog/1139556