如同 Rails 中的其它部分一样,RJS 很好的被合并入框架。这一章,我们看看 RJS 模板如何适应 Rails 的 rest 风格。
很幸运, Rails 提供了一套机制帮助你做代码的调试工作,你可以很快的定位 bug。
默认情况下,在开发模式中全部的 RJS 调用都被包装到 JavaScript try/catch 代码块中try/catch 代码块捕获在 RJS JavaScript 应答执行期间的全部异常。当异常出现时,详细的错误信息出现在两个警告框中。第一个警告框显示异常情况的详细信息。第二个警告框显示出现问题的代码。
在 environments/development.rb 文件中修改 config.action_view.debug_rjs 可以配置调试模式。如果你希望在开发模式中禁用调试,可以把这个参数设为 false 然后重启 web server。
如果 Rails 在 Ajax 请求中出现了一个未经处理的异常,响应返回的是一个 HTML 错误页面而不是我们期望的 JavaScript 代码。有一个很轻松的办法来调式这个问题那就是监视日志。在 Unix 或 Linux 下有一个简单的办法来监视日志,tail 命令。在你项目的根目录执行如下代码,让 tail 来监测日志。
cody> tail -f log/development.log
-f 标记告诉 tail 把输出的信息添加到日志中。
RJS 模板和 Rails 框架完美的结合在了一起,就像 RHTML 和 Builder 模板一样。这意味着 RJS 模板可以像其他类型的模板一样被渲染。同样的,在控制器的 actions 中 render 的大部分选项都可以使用。随后我们要看看 RJS 是如何协同 ActionController 工作的。
默认情况下,控制器回去寻找当前正在被执行的 action 同名的模板文件。需要注意的是控制器在寻找 .rjs 模板之前会首先寻找 .rhtml 或 .rxml 模板。如果你有一个名称为 product.rhtml 的模板和一个 product.rjs 模板,ActionController 会渲染 product.rhtml 并发送将响应 Content-Type 头部设置为 text/html。这样它不会产生你期望得到的结果,并且你在日志中看不到任何错误信息。如果你现在既有 product.rhtml 又有 product.rjs 模板,你可以在 action 中指定你期望渲染哪一个模板类型。
def product
# skip product.rhtml or product.rxml if either exists
render :action => "product.rjs"
end
像你从代码中看到的一样,我们明确的指定了我们需要渲染 RJS 模板。另一个方法是用 respond_to() 代码块配置你期望返回的响应类型。respond_to() 代码块会给 HTTP 响应头部来设定适合的响应类型。远程 Ajax 请求由 Prototype 库指定响应头部是 text/javascript,text/html,application/xml,text/xml,*/*。它告诉 Rails,Ajax 请求喜欢 JavaScript 应答,但是同样接受其他列表中的其他应答类型。下面的代码示例帮助你理解这个概念。
def product
respond_to do |format|
format.html # all html requests
format.js # all ajax requests
format.xml # all XML requests
end
end
上面的 respond_to() 代码块通过 Accept 头部来返回正确的响应类型,例如我们可能用到三个类型: HTML (product.html),JavaScript (product.rjs) 和 XML (product.xml)。你也可以为你能用到响应类型的来自己订制更详细的 respond_to() 代码块。
def product
respond_to do |format|
format.html { flash["notice"] = 'here is a product' }
format.js { render :action => "product_rjs.rjs" }
format.xml { render :xml => @product.to_xml }
end
end
如上所示,你也可以自己订制更详细的 respond_to() 代码块来增加一些自己期望得到的功能。
令人惊讶的,在渲染 RJS 模板时,Rails 自动就会避免渲染布局。所以当渲染一个 RJS 模板时候,你不需要在 action 中指定 :layout => false。
在 controller 内部调用 render 有很多可选的参数,使用 RJS 时你不需要担心他们。表格 1 概述了在 ActionController 中调用 render() 可选的参。
| Option | Works with RJS? | Returns Content-Type = text/javascript? |
|---|---|---|
| :action | Works as expected | Yes |
| :template | Works as expected | Yes |
| :file | Works as expected | Yes |
| :inline | Not useful for RJS | No |
| :partial | Not useful for RJS | Yes |
| :text | Not useful for RJS | No |
Rails 也支持 inline RJS 模板来渲染控制器。这样就避免了因为一个简单的一两行代码就可以完成的任务,我们却不得不创建整个 .rjs 模板文件的情况。
在控制器中的 render() 利用参数 :update 来实现渲染 Inline RJS。怎样在一个 RJS 模板的代码块中定义 render() 调用呢。代码块传递一个 JavaScriptGenerator 实例,就像普通的 RJS 模板。随后控制器的 update action 渲染局部的 header 并用其中的内容替换 id 是 header 的 DOM 元素的 innerHTML。
def update
render :update do |page|
page.replace_html, 'header', :partial => 'header'
end
end
采用 inline 渲染意味着你不需要寻找正在执行的 action 动作同名的 .rjs 模板。Inline 为控制器产生视图代码。如果 inline RJS 代码超过1或者2行,那么更明智的做法是为这个功能创建一个完整的 RJS 模板。
如果在一个 Ajax 请求过程中你需要重定向浏览器,你可以看一下 Rails 的 redirect_to() 方法。Prototype 库不能像浏览器一样对 HTTP 状态代码做出反应,也不能跟随 3xx 重定向代码。还好,JavaScriptGenerator 有 redirect_to() 方法,它能为重定向浏览器产生必要的 JavaScript 代码。
这个新的 redirect_to() 方法由 page 对象在你的 RJS 模板中或控制器的 update 代码中调用。大概通常你都会在控制器的 inline RJS 中使用 redirect_to()。这个新方法和过去我们使用的标准 redirect_to() 方法没啥区别,除了这个新的方法需要由一个 page 对象调用。我们看一个简单的例子,如何在 RJS 中使用重定向。
render :update do |page|
page.redirect_to :controller => 'employees', :action => 'list'
end
这里我们把浏览器重定向到了 EmployeesController 控制的 list 这个 action 。没什么新鲜和令人惊讶的,重定向功能和过去一样,只是它在这里是由一个 page 对象来调用,这个对象由 JavaScriptGenerator 产生,它会创建适当的 JavaScript。
你也可以重定向到一个绝对地址来。
render :update do |page|
page.redirect_to 'http://www.shopify.com'
end
© Railser.cn 里克的网络自习室,仅供学习参考,更新于2008年3月23日