Rails - Ajax and Backbone.JS

好像有一段時間沒寫網誌了!

上週在 Code School 週末免費最後的二十多小時才發現有免費課程,趕緊選了一個進行後,覺得不錯,於是跟老爸討論後決定購買會員資格。

經過一週的苦戰,總算是將十三個課程都全不上過一次。
(不過只看投影片跟進行練習題,沒有看影片,因為有點花時間,所以只能之後慢慢補完)

既然經過如此密集的訓練,功力想必大增,於是今天就來小試身手嘗試了 Rails 的 Ajax 與 Backbone.JS 的搭配。

下面目錄有錯誤之類的請見諒,因為正在練習靠印象打出來,真的有錯誤請通知一下會修正

Mission Initialize


首先,要先把專案環境配置出來。

 cd ~/.pow 
我先切換到 MacOS 上超方便的 Pow 後,建立一個新專案。
 Rails new ajax-test 
接著建立一些基本的Model, Controller, View 等等……
cd ajax-test
rm public/index.html
Rails g controller home
Rails g controller items
Rails g model item name:string description:text

接著設定好 config/router.rb

config/router.rb
1
2
3
4
5
#略
root :to => "home#index"
resources :items, only: [:index]
#略

接著對 home, items controller 建立會用到的 method

app/controllers/home_controller.rb
1
2
3
4
5
#略
truedef index
trueend
#略
app/controllers/items_controller.rb
1
2
3
4
5
#略
truedef index
trueend
#略

到這邊基本上算是完成準備了!

Mission 01


首先,先來對 :remote 的 link 做測試(並沒有特別針對表單,不過原理大致相同)

app/views/home/index.html.erb
1
2
<%= link_to("Items List", items_path, remote: true) %>

然後給 items#index 加個畫面。

app/views/items/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
There is items list.
```
這樣一來就會有一個帶有 data-remote="true" 屬性的連結產生。
(這方面還挺方便的,只要多加個 options 就轉職為 Ajax 了!)
接著打開 http://ajax-test.dev/ 點了一下連結,啥都沒發生。
於是打開 Chrome 的開發人員工具(Command + Alt + I)一探究竟。
確實,有 Ajax 請求,但是傳回的是 HTML 頁面,好像不太對。回想了一下 Code School 課程裡面有要增加 *.js.erb 之類的檔案,先去修改一下 Controller 讓他可以傳回 js 格式的檔案。
``` Ruby app/controllers/items_controller.rb
#略
respond_to :html, :js
truedef index
truetrue@datas = Item.all
truetruerespond_with(@datas)
trueend
#略

再次打開點選連結,會發現 Ajax 雖然一樣傳回網頁,但是卻從包含 layout 變成剩下網頁內容了!

接著,補上 js 部分

app/views/items/index.js.erb
1
2
$("body").text("You already clicked item list.");

這次點選連結後就會直接剩下 You already clicked item list. 這段文字。

看起來不錯,不過如果希望Ajax傳輸是回傳 JSON 格式,要怎麼處理呢?

Mission 02


稍微修改一下 home#index 的 view 讓連結變成傳回 JSON

app/views/home/index.html.erb
1
2
<%= link_to("Items List", items_path, remote: true, "data-type" => "json") %>

再次點選連結,發現沒有被更改。
從開發人員面板看 Networks 的情況,有 Ajax 查詢發生,看一下回應: [ ] 類型是 JSON 看起來生效了,放點資料進去看看。

Rails c
item = Item.new
item.name = "Sword"
item.description = "A weapon"
item.save
exit

再次觀看時就發現有出現,不過頁面仍沒有變化。

這部分可以用 jQuery 去 bind 一些 UJS 的 Ajax 事件去做應對

Mission 03


接著再來把 Backbone.JS 放進去看看~

 cd app/assets/JavaScript/
mkdir lib
mv ~/Downloads/backbone-min.js ./lib
mv ~/Downloads/underscore-min.js ./lib
cd ../../..

複製好檔案後來改 appication.js

app/assets/javascript/application.js
1
2
3
4
5
6
7
#略
//=require jquery
//=require jquery_ujs
//=require lib/underscore-min
//=require lib/backbone-min
#略

這樣就不會先把 Backbone.JS 讀進來了~

然後用 CoffeeScript 來寫 Backbone.JS 的 MVC

這邊就很簡單的寫一下,沒有規劃,畢竟只是要測試看看會發生什麼事情 XDD

app/assets/JavaScript/home.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ ->
trueItemModel = Backbeon.Model.extend()
trueItemCollection = Backbone.Collection.extend({
truetrueurl: '/items',
truetruemodel: ItemModel
true})
true
trueItemView = Backbone.View.extend({
truetruetagName: 'li',
truetruetemplate: _.template("<strong><%= name %></strong>, <%= description %>"),
truetruerender: ->
truetruetrue$(@.el).html(@.template(@.model.toJSON()))
truetruetruereturn @
true})
true
trueItemViewList = Backbone.View.extend({
truetruetagName: 'ul',
truetrueinitialize: ->
truetruetrue@.collection.on('reset', @.render, @)
truetruerender: ->
truetruetrue@.collection.forEach(@.addOne, @)
truetruetruereturn @
truetrueaddOne: (model)->
truetruetrueitemView = new ItemView({model: model})
truetruetrue@.$el.append(itemView.render().el)
true})
trueitems = new ItemCollection()
trueitemList = new ItemViewList({collection: items})
trueitemList.render()
true
true$("body").append("Items List")
true$("body").append(itemList.el)
true
trueitems.fetch()

今天最長的程式碼(笑)

接著打開網頁,就會發現 Items 被列出來了,看起來即使不另外設定也能夠自動讓 Rails 丟出 JSON 格式的資料。

大致上就是這樣了!不過 View 部分需要另外寫一個 template 其實不怎麼方便,如果用 Mission 01 的方法因為還是 erb 可以讓 Server 去 render :partial => “itemList” 之類的,不過 Backbone.JS 似乎就不怎麼方便。這部分只能看情況取捨摟~

做完 Code School 的課程真的有覺得內力大增,至少學到很多優秀的技巧。

留言