通过上一讲,我们已经对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 { render
ml => @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 { render
ml => @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,事实上,比你想象的要简单的多,不是吗?
相关推荐
send(before_method, *args) if respond_to?(before_method) original_method.bind(self).call(*args) end end end ``` 在这个实现中,`instance_method`用于获取原始方法的未绑定版本,`define_method`则用于...
Ruby on Rails的respond_to代码类似物对ASP.NET MVC NuGet 项目: 说明 该库为您的控制器提供了类似响应响应的 RoR 扩展方法。 简而言之, RespondTo允许您的操作根据客户端提交的 *HTTP Accept* 标头以不同的...
在Sinatra中提供对内置Web服务支持的response_to样式Rails块 功能/问题: 根据提供的内容处理内容类型的设置 自动可以调整XMLHttpRequests返回Javascript 根据HTTP_ACCEPT标头解析识别请求。 优先级的顺序是...
respond_to do |format| format.js { render 'sweet_alert_confirm' } end end ``` 这里,`sweet_alert_confirm.js.erb`将包含SweetAlert的JavaScript代码来显示确认对话框。 4. **编写JavaScript视图** ...
我不喜欢在所有操作中编写 rails 的respond_to和/或respond_with 。 但是没有它们,如果请求具有意外的Accept:标头,应用程序会导致 ActionView::MissingTemplate。 示例:请求可能导致错误, AV::MissingTemplate ...
format.csv { send_data render_to_string('users/export.csv.erb'), filename: "users_#{Time.now.strftime('%Y%m%d')}.csv" } end end end ``` 这个`export_csv`方法从数据库中获取所有用户,然后通过`respond...
安装将此行添加到您的应用程序的Gemfile中: gem 'as_csv' , '~> 2.0'基本用法只需在控制器中添加respond_to :csv class WidgetsController < ApplicationController respond_to :xml , :json , :csv def index ...
to_lang是一个Ruby库,它在Google Translate API的支持下将语言翻译方法添加到字符串和数组中。 安装 只需运行: gem install to_lang 用法 要使用to_lang ,需要使用该库,然后使用您的Google Translate API密钥...
if method_sym.to_s =~ /^find_by_(.*)$/ find($1.to_sym => arguments.first) else super end end end ``` 这段代码定义了一个`Legislator`类,并在其上实现了`method_missing`。当尝试调用形如`find_by_...
method可能是Ruby核心Ruby库中缺少的重要方法之一,因此应该很容易将其添加到任何项目中。 这是这样的: require "rbext/blank?" unless Object . new . respond_to? ( :blank? ) 将以上内容与ActiveSupport版本...
安装将其添加到您的Gemfile中: gem 'to_spreadsheet'用法在控制器中: # my_thingies_controller.rbclass MyThingiesController < ApplicationController respond_to :xlsx , :...
- **动态方法调用**:通过`send`和`respond_to?`方法实现动态方法调用。 - **代码生成**:使用`eval`函数在运行时生成代码。 - **动态类和方法定义**:使用`class_eval`方法动态定义类和方法。 #### 3.3 并发编程 -...
在下面的示例中, test_foo仅提供x响应:to_s ,因此永不测试隐式else的值(即,不响应:to_s的x的值) def foo(x) x = x.to_s if x.respond_to? :to_s # ... end def test_foo assert_equal something,
Mobylette 2.0+ deprecated the respond_to_mobile_requests method. Now you must use `include Mobylette::RespondToMobileRequests` instead. to configure it, see the configuration. Also stylesheet and ...
puts symbol.to_s # 输出"hello" ``` **4.7 正则表达式** 正则表达式用于文本模式匹配: ```ruby regex = /hello/ puts "Hello, World!".match(regex) # 输出Match ``` #### 五、代码块和迭代器 **5.1 代码块**...
to_iendsum ( 42 , false )# Sig::ArgumentTypeError:# - Expected false to respond to :to_i# In modulesclass A sig [ Numeric , Numeric ] , Numeric , def mul ( a , b ) a * b endendA . new . mul ( 4 , "3...
}respond_to :json在app / controllers /中创建一个Api控制器class ApiController < ActionController::API include ::ActionController::Serialization respond_to :jsonend将以下gem添加到j
创业板:铁DSL 作者:Rob Morris @ ... 它类似于标准库中的 BasicObject,但具有诸如 #respond_to? 和 #send 是任何真正的 DSL 构建工作所需的。 您可以使用 DslBuilder 或任何其他类作为 DSL 系统的基础。 在任何情况
- **关联**:定义模型之间的关系,如 `has_many`, `belongs_to`, `has_one`, `has_and_belongs_to_many` 等。 - **验证**:确保数据的有效性。 - **回调**:在特定的时间点执行代码。 **5.4 视图和模板** - **ERB*...