最近都在忙Rails app 的网页前端,也花了点时间摸索Rails 下的Ajax。 Rails3 引进了UJS (Unobtrusive JavaScript),也就是不会有像Rails2 一样的inline javascript,但也意味着开发者要对js 有更深入的了解 麻烦 。
简单的介绍
由于不会有inline-javascript,有关一些跳出确认讯息窗跟Ajax的处理都会由public/javascript/rails.js
来负责,Rails3的预设框架是Prototype ,所以如果你比较习惯jQuery的话,可以装官方的jQuery版本 ,然后再把原本那个换掉就好,这边用jQuery来做介绍(因为Rails3.1的预设框架是jQuery ,还真是风水轮流转)。 记得要把config/application.rb
的预设JavaScript档案设定好,很多人(我)以为只要把jquery.js
汇进来就好,忘了jquery_ujs.js
或是汇入的顺序搞错。
config.action_view.javascript_expansions[:defaults] = %w(jquery jquery_ujs)
jquery_ujs.js
这个档案是负责施展魔法的关键,我没有完全看完。 比较要注意的是handleRemote
跟handleMethod
,前者会处理有标记data-remote = "true"
的表单或连结,后者则会处理非Ajax的表单或连接跟加上csrf标记。
remote => true
原先的non-ajax连结或表单只要在后面加上:remote => true
,Rails render出来的html会加上data-remote = "true"
属性,这样也告诉jquery_ujs.js
这个部分要非同步处理。
<%= link_to "Delete", comment, :method => :delete, :remote => true %>
<% form_for @page, :remote => true do %> # 下略
加上那几个字后,重新试试看,你会发先原先的重导向或是render template 都没有效果,这是很正常的,因为预设接受的回应是JavaScript,而我们的伺服端却只有放html 的模版。 如果你不确定是不是真的有传送要求,你可以在开发工具(我用Chrome 的Inspector )里的XHR 栏位里找找已经送出的XHR Request。
JavaScript到底要放在哪?
有很多不同的方法,Rails3 以前可能是用RJS 在伺服端写下Ruby code 然后它会转成对应的JavaScript (用Prototype ) ,不过RJS 跟Prototype 要在Rails3.1 被移出预设的框架了,所以DHH 的建议是要你真的去写JavaScript 不要再仰赖RJS 了,不再有神奇的魔法帮你处理Ajax 了。
所以在Rails3.1 还没释出前,有两种方式撰写JavaScript。
- 你可以选择把JavaScript 放在伺服端当作response 传回,好处是如果你想要用到一些实体变数或辅助方法,你可在尾巴加上.erb,这样可以在回传前先用ERB render 一遍。
def destroy @comment = Comment . find ( params [ :id ] ) @comment . destroy respond_to do | format | format . html { redirect_to comments_path } format . js end end
/* Eliminate the comment by fading it out */ $ ( '#comment_<%= @comment.id %>' ) . fadeOut ( ) ;
- JavaScript 全部放在客户端,这样的好处是比较好管理,毕竟大部分的逻辑都是在处理DOM ,不过这时与伺服器沟通就要仰赖指定的资料格式,可以用JSON 传回整个物件交由客户端决定如何显示,或传回HTML 再塞进页面里,或者干脆直接传回文字。 关于客户端的JavaScript ,
jquery_ujs.js
提供了与jQuery Ajax的对应的全域事件,会在处理标有data-remote = "true"
的表单或连结时被触发。 你只要把你要的方法绑在特定的事件上就可以了。$ ( "a[data-remote]" ) . live ( "ajax:beforeSend" , function ( xhr , settings ) { $ ( this ) . parent ( ) . effect ( "highlight" ) ; } ) . live ( "ajax:success" , function ( xhr , data , status ) { $ ( this ) . parent ( ) . fadeOut ( ) ; } ) . live ( "ajax:error" , function ( evt , xhr , status , error ) { alert ( xhr . responseText ) ; } ) ;
来杯咖啡吧!
觉得JavaScript 很不好写,写起来很不舒服吗? ,Rails3.1会把CoffeeScript当作预设的客户端脚本语言,不知道它是什么吗? 写一整天的JavaScript 再回头看看它的网站,你就会爱上它了。
结语
Rails 把开发Ajax 的责任递给了开发者,这也意味着我们与要对自己的code 负责,要对JavaScript 有更深入的了解。 而我大概也要去恶补一下我的JavaScript 了(笑)。