跨越邊界: Ajax on Rails

來源:互聯網
上載者:User

轉自IBM技術網站

對 Ajax 這種使 Web 頁面更具互動性的技術的大肆宣傳已成過度之勢。Ruby on Rails 架構和 Ajax 的完美整合所產生的力量在一定程度上促成了該架構的繁榮。本文旨在揭示:是什麼使 Ajax on Rails 成為如此強大的組合。

跨越邊界 系列之前的兩篇文章(參見 參考資料)全面介紹了 Streamlined,這是 Rails 的輔助架構,該架構有效地利用 scaffolding 來快速產生簡單的、使用 Ajax 的使用者介面。除非您一直與世隔絕,不然您一定會知道 Ajax 是這樣一種編程技術,它使用 XML、JavaScript 和 Web 標準來建立高度互動性的 Web 頁面,正如您在 Google Maps 和大量其他網站上所看到的頁面那樣。許多讀過 Streamlined 文章的讀者都要求我描述一下 Ajax 在 Ruby on Rails 上的運行方式。本文全面介紹了兩個簡單的 Ajax 例子,延著這個思路介紹了 Ruby/Ajax 這一組合如此成功的原因。在本系列的下篇文章中,我將探究 JavaScript 這門程式設計語言。

Ajax 定義

Ajax 代表 Asynchronous JavaScript + XML。資訊架構師 Jesse James Garrett 於 2005 年提出這一術語,該術語用來描述一門在夾縫中生存了近二十年的技術(參見 參考資料)。Ajax 的使用隨即爆增,不論在圖書館、流行網站還是文獻作品中都保持同步增長。

Ajax 重新定義了基本的瀏覽器使用模型。原模型一次呈現一個頁面。Ajax 允許瀏覽器在頁面更新的間隔同伺服器進行交流。這樣做的好處是帶來更加豐富的客戶體驗,但卻以增加複雜度為代價。Ajax 是這樣啟動並執行:使用 JavaScript 用戶端庫在客戶機和伺服器間發送 XML。Ajax 開發人員可以在任何時刻從客戶機發送非同步請求,因而在伺服器處理這些請求時,使用者互動可以繼續進行。下面就是 Ajax 請求的流程:

關於本系列

在 跨越邊界系列 文章中,作者 Bruce Tate 提出這樣一種觀點,即當今的 Java 程式員們可以通過學習其他方法和語言很好地武裝自己。自從 Java 技術明顯成為所有開發項目最好的選擇以來,編程前景已經發生了改變。其他架構影響著 Java 架構的構建方式,從其他語言學到的概念也可以影響 Java 編程。您編寫的 Python(或 Ruby、Smalltalk 等語言)代碼可以改變編寫 Java 代碼的方式。

本系列介紹與 Java 開發完全不同的編程概念和技術,但是這些概念和技術也可以直接應用於 Java 開發。在某些情況下,需要整合這些技術來利用它們。在其他情況下,可以直接應用概念。具體的工具並不重要,重要的是其他語言和架構可以影響 Java 社區中的開發人員、架構,甚至是基本方式。

  1. 一個事件(如使用者的滑鼠點擊或編程計時器的觸發)啟動一個 JavaScript 函數。

  2. JavaScript 函數為部分頁面而不是整個頁面建立一個請求。JavaScript 隨後通過 HTTP 將該請求發送到 Web 服務器。
  3. 此 HTTP 要求調用伺服器上的一個指令碼,如 Rails 控制器方法或 Java servlet。
  4. 該伺服器指令碼建立一個 XML 文檔並將其返回給伺服器。
  5. 在接收結果的同時,客戶機非同步處理建立、更新或刪除部分 Web 頁面,如列表元素、div 標記或映像。

所有 Ajax 應用程式都使用類似這種順序的一種方法。例如,某個應用程式允許將字典中的單詞與其定義一起儲存。舊式的應用程式會強迫您用一個新的整頁模式來編輯定義。Ajax 允許原地編輯,它用一個條目欄位替換定義文本,然後用更新的定義來替換該表單。

Ajax 解決方案的組件是:

  • 用戶端 JavaScript 庫,用來管理非同步請求。
  • 伺服器端 JavaScript 庫,用來處理進來的請求,並構造一個 XML 響應。
  • 用戶端 JavaScript 庫,用來處理產生的 XML。
  • 稱作文件物件模型(DOM)的庫,允許對現有 Web 頁面進行更新。
  • 輔助常式,用來處理不可避免的 UI 和整合問題。

事件/請求/響應/替換模型是大多數 Ajax 應用程式的核心模型,但如果您剛接觸 Ajax,您一定會對 Ajax 中大量的可用庫和這些庫之間巨大的差別感到驚訝不已。該領域中有許多 Ajax 架構,它們的功能常常重疊且沒有確定的勝出者。單就 Java 市場而言,有許多庫可用,包括 Echo、Dojo、DWR、Google Web Toolkit(GWT)、Java Web Parts、AjaxAnywhere、AjaxTags、Scriptaculous 和 Prototype。這些架構使用截然不同的方法。一些架構試圖通過產生 JavaScript 代碼的 Java 庫來隱藏 JavaScript,如 GWT。另一些架構致力於使 JavaScript 更易使用。一些相當地全面,如 Dom4J,而另一些則僅著力於解決好一個小問題。由於有許多流行的新技術,解決方案之間互相割據的場面有時會很難駕馭,調試工具、UI 實踐(如 Back 按鈕)和明智的開發實踐的實現非常緩慢。Java 平台上的 Ajax 庫的力量源自其多樣性。這也正是其缺點所在,因為多樣性導致了難以決斷、整合方面的顧慮和複雜性。

有了 Ruby on Rails,開發體驗就顯著不同了,這是由於兩個原因。首先,Ruby on Rails 有一個核心的 Web 開發平台:Ruby on Rails。其次,到目前為止,大多數在 Rails 上的 Ajax 開發體驗都圍繞著兩個核心架構:Scriptaculous 和 Prototype(參見 參考資料)。Rails 方法使用運行時代碼產生和定製標記,這使您不必理會複雜的 JavaScript。是時候自己來實踐了。如果您想要在學習本文的過程中編寫代碼的話,需要下載 Rails,也要下載必要的 Ajax 架構(參見 參考資料)。開啟您的 Rails 環境,跟我一起來吧。



回頁首

沒有 Ajax 的簡單的 Rails 應用程式

要使用 Rails 和 Ajax,就要建立一個空項目,並產生一個有兩個方法的控制器。一個控制器控制簡單的頁面,另一個控制器建立一個 Ajax 響應。鍵入下列代碼:

rails ajax            cd ajax            script/generate controller ajax show time

第一行和第二行代碼產生一個 Rails 項目,並切換到新目錄。第三行代碼產生一個叫做 ajax 的控制器,並查看兩個動作:showtime。清單 1 顯示了該控制器的代碼:

清單 1. 有兩個空方法的控制器

            class AjaxController < ApplicationController            def show            end            def time            end            end            

首先在不使用 Ajax 的情況下構建兩個簡單視圖,然後用 Ajax 將這兩個視圖綁定到一起。編輯 app/views/ajax 中的 show.rhtml 視圖,使它和清單 2 類似:

清單 2. 簡單視圖

            <h1>Ajax show</h1>            Click this link to show the current <%= link_to "time", :action => "time" %>.            

清單 1 和清單 2 中的代碼不支援 Ajax,但我還是會仔細分析該代碼。首先,看清單 1 中的控制器。兩個空的控制器方法處理進來的 HTTP 要求。如果不明確地呈現一個視圖(使用 render 方法),Rails 會呈現和該方法同名的視圖。由於 Scriptaculous 和 Prototype 庫也使用 HTTP,Rails 不需要對標準 HTTP 方法和 Ajax 方法進行區分。

現在將注意力轉移到清單 2 中的視圖。大多數代碼都是簡單的 HTML 程式碼,只有第二行的 link_to 輔助常式例外:<%= link_to "time", :action => "time" %>

正如在跨越邊界 之前的文章中所看到的那樣,Ruby 用其運算式的值替代 <%=h%> 之間的代碼。在這個樣本中,link-to 方法是一個產生簡單 HTML 連結的輔助常式。可以通過執行該代碼看到該連結。通過鍵入 script/server 啟動伺服器,然後將瀏覽器指向 http://localhost:3000/ajax/show 。您將看到圖 1 中的視圖:

圖 1. 不涉及 Ajax 的簡單使用者介面

在瀏覽器中,單擊功能表項目來查看頁面原始碼(在 Internet Explorer 為 View > Source ,在 Firefox 中為 View > Page Source)。您將看到清單 3 中的代碼:

清單 3. 由 show.rhtml 產生的視圖

            <h1>Ajax show</h1>            Click this link to show the current <a href="/ajax/time">time</a>.            

請注意清單 3 中的連結代碼。該模板讓 Rails 使用者不必面對冗長且容易出錯的 HTML 句法。(Ajax 代碼也是這樣運行:使用輔助方法插入 JavaScript 代碼,該代碼替您管理遠程請求和 HTML 替換。)如果單擊該連結,將看到針對 time 方法的預設視圖,但我還沒有實現它。為加以補救,請用清單 4 中的代碼替換 app/controllers/ajax_controller.rb 中的 time 方法。為保持簡單,我直接從控制器中呈現視圖。稍後,我會把一切處理好並呈現視圖。

清單 4. 呈現時間

            def time            render_text "The current time is #{Time.now.to_s}"            end            

現在,當單擊該連結時,會得到圖 2 中的視圖:

圖 2. 不涉及 Ajax 的視圖

很快就能看到這個 UI 的一個問題。這兩個視圖不從屬於單獨的頁面。該應用程式表示一個單一概念:單擊一個連結來顯示時間。為反覆更新時間,每次都需要單擊該連結和 Back 按鈕。將該連結和時間放到相同的頁面中也許可以解決這個問題。但如果該頁面變得非常大或非常複雜,重新顯示整個頁面會很浪費,也會很複雜。



回頁首

添加 Ajax

Ajax 讓您可以只更新 Web 頁面的一個片段。Rails 庫為您處理大部分的工作。要將 Ajax 添加到這個應用程式中,需要以下四個步驟:

  1. 配置 Rails 以使用 JavaScript。
  2. 更改時間連結來提交 JavaScript Ajax 請求,而不是僅呈現一個 HTML 連結。
  3. 指定要更新的 HTML 片斷。
  4. 為更新的 HTML 內容準備一個位置。
  5. 構建一個控制器方法,或者一個視圖來呈現 Ajax 響應。

首先,更改 app/views/ajax/show.rhtml 中的代碼,使其與清單 5 類似:

清單 5. 更改顯示視圖來使用 Ajax

            <%= javascript_include_tag :defaults %>            <h1>Ajax show</h1>            Click this link to show the current            <%= link_to_remote "time",            :update => 'time_div',            :url => {:action => "time"} %>.<br/>            <div id='time_div'>            </div>            

我做了一些更改。首先,為處理配置,簡單地將必要的 JavaScript 庫直接包含在視圖中。通常,還會有更多的視圖,為避免重複,我將 JavaScript 檔案包含在一個公用的 Rails 組件中,如 Rails 布局。本例只有一個視圖,所以一切從簡。

其次,我改變了連結標記來使用 link_to_remote。您一會兒就能看到這個連結的作用。請注意下列三個參數:

  • 連結文本:從非 Ajax 的例子中照搬過來。

  • :update 參數。如果您以前沒見過這種文法,那麼就把 :update => 'time_div' 當作是一個已命名的參數,其中的 :update 是名稱,update_div 是值。此代碼告訴 Prototype 庫:此連結中的結果將用 time_div 這一名稱更新 HTML 元件。
  • 代碼 :url => {:action => "time"} 指定該連結將調用的 URL。:url 從一個雜湊映射表中擷取值。在實際中,該雜湊映射表只有一個針對控制器動作的元素::time。理論上,該 URL 也可以包含控制器的名稱和控制器需要的任何選擇性參數。

在清單 5 中,還可以看到空的 div,Rails 將用目前時間更新它。

在瀏覽器中,裝載頁面 http://localhost:3000/ajax/show。單擊該連結,將看到圖 3 中的結果。

圖 3. 含 Ajax 的視圖

為了很好地瞭解這裡發生的情況,請查看該 Web 頁面的原始碼。清單 6 顯示了該代碼:

清單 6. 顯示模板的結果(在啟用 Ajax 的情況下)

            <script src="/javascripts/prototype.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/effects.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/dragdrop.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/controls.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/application.js?1159113688" type="text/javascript"></script>            <h1>Ajax show</h1>            Click this link to show the current            <a href="#" onclick="new Ajax.Updater(            'time_div', '/ajax/time', {asynchronous:true, evalScripts:true});            return false;">time</a>.<br/>            <div id='time_div'>            </div>            

請注意包含的 JavaScript 列表。Rails 輔助方法(include_javascript_tags :defaults)為您構建了此列表。接下來,看到一個用來構建新的 Ajax.Updater 對象的 JavaScript 函數調用,而不是一個 HTML 連結。正如您所料想的那樣,名為 asynchronous 的參數被設定為 true。最後,在 HTML div 標記中看不到值,這是由於初始頁面在那裡沒有值。



回頁首

使用其他 Ajax 選項

Ajax 能產生強大的動作,甚至能產生一些預料不到的動作。例如,使用者也許沒注意到更新的時間連結。link_to_remote 選項讓您能夠輕易地將特殊效果應用到該條目上,從而讓使用者注意到該結果。現在將應用一些效果。請更改 show.rhtml 中的 link_to_remote 輔助方法,使它與清單 7 類似:

清單 7. 添加效果

            <%= link_to_remote "time",            :update => 'time_div',            :url => {:action => "time"},            :complete => "new Effect.Highlight('time_div')" %>            

最佳 Ajax 效果會使您的更改獲得臨時的關注,但卻不會永久持續。您的目標應該是把變更提示給使用者,而不打斷他們的工作流程。像這種用黃色來弱化強調的技術,或用滑入內容或淡出內容來讓使用者注意的技術都不是長久之計。

到目前為止,連結是您見到的惟一觸發器。Ajax 還有許多其他的可用武器,一些由使用者驅動,而另一些由程式事件驅動,如時鐘。它是一個像鬧鐘一樣並不需要使用者幹預的東西。可以用 Ajax 的 periodically_call_remote 方法定期更新時鐘。請按照清單 8 編輯 show.rhtml 中的代碼:

清單 8. 定期調用遠程方法

            <%= javascript_include_tag :defaults %>            <h1>Ajax show</h1>            <%= periodically_call_remote :update => 'time_div',            :url => {:action => "time"},            :frequency => 1.0 %>            <div id='time_div'>            </div>            

圖 4 顯示了結果:不需要使用者幹預,每隔一秒鐘進行更新的時鐘:

圖 4. 用 Ajax 定期更新的時鐘

儘管 Rails 視圖中的代碼和不含 Ajax 的版本相似,但背後的代碼卻很不同:此版本使用 JavaScript 代替了 HTML。可以通過在瀏覽器中查看原始碼看到清單 9 中的代碼:

清單 9. periodically_call_remote 的原始碼

            <script src="/javascripts/prototype.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/effects.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/dragdrop.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/controls.js?1159113688" type="text/javascript"></script>            <script src="/javascripts/application.js?1159113688" type="text/javascript"></script>            <h1>Ajax show</h1>            <script type="text/javascript">            //<![CDATA[            new PeriodicalExecuter(function() {new Ajax.Updater(            'time_div', '/ajax/time', {asynchronous:true, evalScripts:true})}, 1.0)            //]]>            </script>            <div id='time_div'>            </div>            

請一定注意這裡發生的情況。您正在一個更高層的抽象之上有效地工作,而不是使用小塊的自訂 JavaScript 片段,Ruby on Rails 模板系統使使用模型變得相當自然。

正如之前提到的那樣,我正從控制器中直接呈現文本。這一簡化使開始編程變得很容易,但卻不能一直持續下去。視圖應該處理顯示,控制器應該在視圖和模型間調度資料。這項設計技術叫做模型-視圖-控制器(MVC),它使對視圖或模型的更改更容易分隔開。為使這個應用程式符合 MVC,可以讓 Rails 呈現預設視圖,正如預料的那樣,該內容將替代 time-div 之前的內容。請按照清單 10 更改 app/controllers/ajax_controller.rb 中的 time 方法:

清單 10. 重構

            def time            @time = Time.now            end            

請按照清單 11 更改 app/views/ajax/time.rhtml 中的視圖:

清單 11. 使用視圖呈現 Ajax 內容

            <p>The current time is <%=h @time %></p>            

控制器方法設定一個名為 @time 的執行個體變數。由於控制器什麼都沒明確地呈現出來,Rails 將 time.rhtml 視圖呈現出來。這種使用模型和呈現一個不含 Ajax 的視圖完全一致。 可以再一次看到,Rails 使開發人員不必考慮使用 Ajax 和不使用 Ajax 的應用程式間的區別。從傳統的 Web 應用程式到 Ajax,該使用模型都驚人地相似。由於使用 Ajax 的成本如此之低,越來越多的 Rails 應用程式都開始利用 Ajax。



回頁首

Rails 中 Ajax 的其他用法

Rails Ajax 體驗領域寬廣且內容深刻 —— 我無法用單篇文章甚至一系列文章來概括其深刻的內容。我只能指出 Rails Ajax 支援可以解決其他一些問題。下面是 Rails 中 Ajax 的一些通常用法:

  • 提交遠端資料表單。 除了必須非同步提交以外,Rails 中的 Ajax 表單和傳統表單的執行方式完全一樣。這意味著 Rails 中的 Forms 輔助標記讓您必須指定一個要更新的 URL,執行可視化的效果,正如使用 link_to_remote 一樣。正如 link-to-remote 擴充了 link_to 輔助方法一樣,Rails submit_to_remote 擴充了一個 Rails submit 輔助方法。

  • 執行複雜指令碼。 Rails 開發人員常常需要執行複雜的指令碼,遠不止更新單個 div 和執行效果那麼簡單。為此,Rails 提供 JavaScript 模板。用 JavaScript 模板,可以將任意 JavaScript 指令碼作為 Ajax 請求的結果來執行。這些模板的一些常見用法(叫作 RJS 模板)為更新多個 div、處理表單驗證和管理 Ajax 錯誤情境。
  • 拼字補全。 您一定想基於資料庫中的條目為您的使用者提供拼字補全服務。例如,如果使用者鍵入 Bru,我想讓我的應用程式注意到資料庫中 “Bruce Tate” 這個值。可以使用 Ajax 定期檢查欄位的更改,並根據使用者鍵入的內容發送拼字補全建議。
  • 動態構建複雜表單。 在業務領域裡,常常需要查看部分已完成表單,然後才能知道使用者應該完成哪個欄位。例如,如果使用者擁有一些特定種類的收入或費用,那麼 1040EZ 納稅單是無效的。可以在這個過程中用 Ajax 更新表單。
  • 拖放。 可以用 Rails 快速實現拖放支援,這比大多數其他架構要省力得多。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.