3/27/2007

Ajax auto-update

Ajax 跟 Ruby on Rails 的整合已經眾所皆知,今天心血來潮,想來實做 digg-spy 形式的資料更新。但是我的需求是每隔一段固定的時間更新,而不是一直 append 新的訊息。在參考了幾個網站後,驚訝的發現,這種 auto-update 的 Ajax 怎麼可以這麼簡單(請用 thegiive 的口氣自行想像)。

*** 斜體字為你尚未命名或已經命名好的名稱 ***

[summary] 我們得準備:
  • 一個 controller 裡面的新的 action,假設該 action 名稱為 action-name,該 controller 名稱為 controller-name
  • 一份 RJS template,置放在 /app/views/controller-name/action-name.rjs。
  • 一份 partial template,假設置放在 /app/views/controller-name/_show_topics.rhtml。
  • 在適當的地方加入 javascript。


step 0:
首先在預設的 layout 中掛入 prototype 等 JavaScript。寫法如下:

<%= javascript_include_tag :defaults %>

其中 :defaults 會將 /public/javascripts/ 中預設的 JavaScript 都掛載上來。如果不想全部掛上來的話,可以改寫成 :script-name

step 1:
接著在你的 controller 裡面寫入一個新的 action。假設我們想要每分鐘更新文章列表:

def update_topics
# 取出最新的 forum 文章,get_all_topics 請自己在 model / controller 撰寫
@all_topics = get_all_topics(10) # hard code 是不好的,小朋友不要學。也可以順便做錯誤處理。
end

step 2:
接著是你必須建立一個檔案 /app/views/controller-name/action-name.rjs,在這個 RJS template 裡面使用 prototype helper 裡面的 methods 來與瀏覽器溝通。內容如下:

page.replace_html 'update-topics-div', :partial => 'show_topics', :object => @all_topics
page.visual_effect :highlight, "update-topics-div"

我們用了 replace.html 來幫我們做取代的動作,如果是 digg-spy-style 的話,通常我們會用 insert.html,有空再來寫。值得注意的是,在這個檔案裡面無須使用 <%%> 來內嵌,直接撰寫即可。update-topics-div 這邊代表的是欲取代的 html element id,show_topics 則是欲取代的 partial template(注意 template 的命名有 prefix _,render 時無須 prefix _,也無須副檔名),再利用 :object 將變數 binding 到 template。visual_effect 效果我就不介紹了。

step 3:
當然你要有輸出的 view,我們假設是 /app/views/controller-name/another-action-name.rhtml。部份的片段應該有:

...
<%= render :partial => 'show_topics' %>
...

而我們的 template _show_topics.rhtml 假設長成這個樣子:

<div id='update-topics-div'>
<ul>
<% @all_topics.each{ |topic| %>
<li><%= topic.title %></li>
<% } %>
</ul>
</div>

step 4:
最後我們挑選一個適當的地方加入 JavaScript,什麼叫適當的地方呢?因為有些 template 會共用的關係,如果把 JavaScript 加入到共用的 template,會出現 RJS 找不到 html element id 的錯誤,所以說得擺在適當的地方,當然跟瀏覽器的支援程度也有關係。假設找到了適當的地方,則我們加入 JavaScript 如下所示:

var updateInterval = 60 * 1000; // 每分鐘 update 一次
var timer;

function goUpdateTopics() {
timer = setInterval('updateTopics()', updateTopicsInterval);
}

function updateTopics() {
// url 記得寫對!
url = "/controller-name/action-name";
new Ajax.Request(url, {
asynchronous: true,
method: "get",
});
}
goUpdateTopics();


Well, 經過這四步驟,你應該已經可以快樂地使用 Ajax 整合在 Rails 裡所提供的功能與樂趣。:)

延伸閱讀

沒有留言: