RSS 放送

Rails3 Ajax 筆記

Posted on

最近都在忙 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 這個檔案是負責施展魔法的關鍵,我沒有完全看完。比較要注意的是 handleRemotehandleMethod ,前者會處理有標記 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。

  1. 你可以選擇把 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();

    Code來源

  2. 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);
            });

來杯咖啡吧!

來源 RailsCast

覺得 JavaScript 很不好寫,寫起來很不舒服嗎?,Rails3.1 會把 CoffeeScript 當作預設的客戶端腳本語言,不知道它是什麼嗎?寫一整天的 JavaScript 再回頭看看它的網站,你就會愛上它了。

結語

Rails 把開發 Ajax 的責任遞給了開發者,這也意味著我們與要對自己的 code 負責,要對 JavaScript 有更深入的了解。而我大概也要去惡補一下我的 JavaScript 了(笑)。

About zetachang

Love to program and love to hack problems.

一則回應 »

  1. 我跟着书写rails3和ajax,用了rjs的方法始终不能运行,换成了erb可以了,看来rails真得越来越让我们开发者陷入复杂的境地喽!

    回應
  2. I’m very happy to discover this great site. I want to to thank you for ones time for this fantastic read!! I definitely enjoyed every part of it and i also have you saved as a favorite to look at new stuff on your site.

    回應
  3. My partner and I absolutely love your blog and find
    a lot of your post’s to be exactly I’m looking for.
    Do you offer guest writers to write content available for you?

    I wouldn’t mind writing a post or elaborating on most of the subjects you write about here. Again, awesome weblog!

    回應
  4. Hello there, I discovered your blog via Google
    at the same time as looking for a similar topic, your web site came up,
    it appears good. I’ve bookmarked it in my google bookmarks.

    Hello there, simply changed into aware of your blog via Google,
    and found that it is truly informative. I’m going to be careful
    for brussels. I will be grateful for those who proceed this in future.

    Numerous folks might be benefited from your writing. Cheers!

    回應

發表留言