自从写了Rails 3 Remote Links & Forms Definitive Guide有一个问题也接踵而至:
我们该如何使远程链接或者表单取回 js.erb而不是一个html的partial?
在上一篇中,我们请求一个html partial并通过ajax回调插入到页面中.但如果我们想要javascript被执行?或者XML、JSON被解析?又或者显示出纯文本呢?
Equal parts Rails & jQuery
首先,我们需要明白Rails3中 :remote => true 的过程. It’s equal parts Rails and jQuery magic.但表担心,这只是一个小魔术,捆绑成4个步骤的过程: 1. Rails告诉jQuery,“哥们,把你的ajax绑定到这霸气的表单/链接”,通过 :remote => true 这个选项. 2. jQuery劫持?元素的click/submit事件并绑定到.ajax()方法.现在,元素提交通过使用ajax取代在浏览器中加载一个新页面. 3. 当这个元素被click/submit时,Rails接收到ajax网页请求并响应以一些内容. 4. jQuery接收到响应的内容有.ajax()方法hi-jacked在我们的的元素中,并为我们提供回调用以在页面中处理这个响应.
在这篇文章中,我们正在探索各种各样的、使我们能够指定ajax的响应格式并据此做出处理的方式,这实际上涵盖上述所有4个步骤.
步骤 1 & 2:设置data-type
当浏览器发送web请求,在浏览器到服务器,服务器返回浏览器的过程中,部分 请求/响应 的header能够指定内容的格式.当在浏览器中加载一个页面,内容的类型通常从url的拓展可以推断得出.尽管如此,jQuery能够直接在ajax请求的header部分设置我们所想要的data-type.
jQuery允许dataType参数
jQuery的.ajax()方法提供一个可选的dataType参数用以指定我们所想要的响应data-type.这允许jQuery在请求的HTTP Accept header指定格式类型,然后封装响应的内容到适当的数据对象使得更容易操作.
在jQuery1.4中,如果你不指定响应的data-type,jQuery会检查响应的MIME类型头并智能的猜测其为data-type,动态的转换响应对象的data-type
在.ajax()文档页面有更多的信息,但基本的类型有如下:
Rails.js设置dataType参数
Rails UJS驱动通过我们在远程链接/表单中指定的data-type属性来设置我们的ajax dataType参数.如果我们不明确地指定data-type,那默认的data-type将使用公有的$.ajaxSettings.如果我们没有提前设置它,那么一个通用的请求发送出后将会收到任意类型的响应.
|
|
老版本的UJS驱动会默认一个在script 中的data-type,而不是发送一个通用的请求.看上去,这像是一个明智的做法,但如果在我们controller的action中没有定义format.js的话, Rails将会抛出一个异常. 而在较新版本的UJS驱动中则简单地使用jQuery的’/‘默认dataType.这会告诉服务器,“不管你收到什么都给我”.然而,这会让controller响应以在Responder中所列出的第一种格式(见下一节).这样的话,如果 format.html 列在 format.js 前面的话,app会响应以HTML格式(这意味着将会尝试跳转到POST或DELETE方法的ajax请求).这并不是我们想要的.
所以在最新版本的UJS驱动中,我们找到如何设置默认情况,比如说,当它告诉服务器,“尽管我更希望得到JS格式,但我会得到所有你得到的.“这样,如果所有可用的响应格式包括format.js都被定义,那么返回的将会是JS格式.当然,如果format.js没有被定义,那controller将会继续按照列表顺序返回第一个.
|
|
步骤 3 :在Rails的controller中的响应
现在我们已经有了一个ajax请求,同时,在该请求的header指定我们希望得到的data-type.我们的Rails app接收到这个请求,就会路由到相应的action,并渲染出一个响应.
我们的controller决定渲染些什么内容作为响应,以及是什么样的格式.respond_with 和 respond_to 这两个在Rails的Responder类中的方法会检查请求的 Accept 头(通过dataType设置)以渲染出适当的响应.
对于基于对象的data-types,如XML和JSON,我们通常会对其序列化并返回一个指定格式的对象.这就是Responder默认所做的.而对于给予内容的data-types,如JS或html,我们通常会渲染一个 js.erb 或 html.erb 文件.
技术上,我们也能有一个自定义的 json.erb 或 xml.erb模板来渲染一个自定义的数据对象.Responder会查找这些模板,如果存在则渲染之.
步骤 4 : jQuery处理响应
从上一篇文章可知,我们绑定了我们处理响应的jQuery代码在ajax:success,ajax:error,ajax:complete这些回调中.
现在,我们对于各种不同的data-types及如何设置它们有了新的认识,我们能够修改我们的响应回调来处理我们所想要的data-type.在上一篇文章中,我们的回调绑定处理了一个HTML响应.
处理HTML响应:
|
|
同样的,我们能很轻易的修改上面的代码来处理JSON响应:
处理JSON请求:
|
|
最后,如果是要处理一个JS请求,则我们不需要绑定任何的回调函数.记住,如果是 data-type: ‘script’ ,jQuery会自动执行页面中的JavaScript响应.
处理JS请求:
|
|
如果 我们的响应没有自动为我们执行,那我们的处理方式可能是像下面这样:
|
|
注意,我们已经绑定了回调 ajax:complete 来取代ajax:success|error.这是因为,我们的success/error处理都在js.erb文件.
上面的处理方式并不非完全和自动执行函数一致.上述的函数会在 $('#i-want-js’) 元素的上下文执行我们的脚本,同时,jQuery在 $(window) 上下文自动执行我们的脚本.
现在,让我们来个总结
使用js.erb的例子
就像上一篇文章,我们会创建一个comment并通过ajax提交.所不同的是,这次我们会响应以 js.erb
在controller中,我们会添加一些响应html、hs、json请求的功能.
comments_controller.rb
|
|
如果你对Rails3的Responder不熟悉,下面的代码效果是一样的:
|
|
现在,我们来设定index页面来列出所有的comments,以及包括我们的ajax表单用以创建一个新comment.我们不需要在我们的表单中写任何data-type这鸽HTML5属性,Rails UJS会默认我们需要JS
index.html.erb
|
|
最后,我们需要创建 js.erb模板,该模板会被执行并插入响应到我们的页面中.
create.js.erb
|
|
写在最后!
重申一次,这里我们不需要绑定任何ajax回调.It just works.
有时候,javascript响应不会像它本应该的那样执行,取而代之的是作为一个字符串返回.这通常意味着有在这个响应的javascript中有一些异常.这是很烦人的,但它不会从自动执行响应中抛出任何可见的javascript错误.
See Rails js.erb Remote Response not Executing.