看板 Web_Design 關於我們 聯絡資訊
我最近在做 Rails + Angular CRUD , 我是 Rails 寫很久最近開始寫 Angular, 我想我可以分享一些經驗。 首先你要把 Angular CRUD 和 Rails CRUD 分開來看, Angular 的資料不管怎麼改,都是存在前端的 JavaScript 的記憶體裡面, 沒有後送到 Server 的話 Server 都不知道。 Angular 做為一個前端 framework 是不需要管後端怎麼做的, 在拿資料的時候是用 JSON 拿沒錯,但存回 server 的時候還是得用 Ajax 打回去。 具體的做法是這樣: // in controller $http.post("/articles", { title: "New Article 1", content: "..." }) .then(function(response) { /* 存好了 */ }); 打開 Chrome 的 Inspector 的 Network ,你會看到有個 request 過去。 那麼,既然都用 Ajax 存資料到後端了,取得資料當然也用 Ajax 做: $http.get("/articles/1") .then(function(response) { $scope.article = response; } 後端出 JSON 用 respond_with 你應該不陌生。 到這裡為止,你可以參考 Angular 官方的 Tutorial "PhoneCat" http://docs.angularjs.org/tutorial/step_00 它會一步一步教到用 $resource 來跟後端 RESTful Server 存取資料。 不過呢,預設的 Angular $http 是沒辦法接上 Rails 的 原因有二,一個是 $http 少送一個 header 叫 X-Requested-With=XMLHttpRequest 大部份的 Ajax Library 都有送,就它沒送,所以它認不出 POST by Ajax。 所以要去偷改 $httpProvider: app.config([ '$httpProvider', function($httpProvider) { $httpProvider.defaults.headers .common["X-Requested-With"] = "XMLHttpRequest"; } ]); 這樣 Rails 就能正確解出 POST by Ajax 了。 第二個是 CSRF Token 的傳法 Rails 一般的表單做法是藏在 Form 裡面有個 hidden input, Rails 傳統的 Ajax 用 UJS 會自動讀 meta 裡面的 CSRF Token 但 Angular 是用 Header 傳,並且取第一次連線時的 cookie['XSRF-TOKEN'], 於是你要 hack 一下 controller 讓它送出這個 cookie 並且讓 Rails 去認 Angular 傳來的 Token in Header 詳細:http://stackoverflow.com/a/15761835 最後是關於 $resource 的一些 caveats $resource 跟 restangular 我都用過, 最後是覺得後者的 DSL 太難記,前者就單純是 CRUD ,比較好學。 首先是 Rails 的 "Update" 通常是 PATCH 或 PUT, 所以官方文件裡面的範例的 article.$save 在 Rails 不太實用(它是送 POST) 在 $resource 裡面要這樣定義(其實文件裡面也有提到): var Article = $resource("/articles/:id", { // default options id: "@id" // 表示自動取用 Article class 的 instance 的 "id" property }, { // custom actions update: { method: "PUT" // 定義 article.$update 送 PUT request } }); 至於存的時候是這樣存: // 先更新 JavaScript 物件的資料 $scope.article.title = "New Title"; // 或是 ng-model 綁到 input $scope.article.content = "New Content"; // 戳 "update" button 的時候 $scope.article.$update .then(function(article) { // Rails 傳回 show.json // 然後一個一個欄位更新 // 不要直接 $scope.article = article,不然會變成不是 $resource 的物件 for (var property in article) { if (article.hasOwnProperty(property)) { $scope.article[property] = article[property]; } }, function(response) { // 儲存失敗,Rails 直接 render :json => { :errors => @article.errors } $scope.errors = response.data.errors; // 然後你在 view 裡面用 ng-if 去 render errors }); 如果是 nested 的場合是這樣: var Comment = $resource("/articles/:articleId/comments/:id", { id: "@id", articleId: $scope.article.id }, { // 略 }); 也配合 ng-route 或 Angular UI-Router 可以從 #/ 裡面取得 article id 。 custom member action 的做法是這樣(以「把某噗靜音」為例): var Plurk = $resource("/plurks/:id/:action", { id: "@id", action: "" // 預設把 action 填空字串 }, { mute: { method: "POST", params: { action: "mute" // 把 action 填入 "mute" } } }); 這樣子 plurk.$mute() 就會送出 POST /plurks/123/mute 了。 但 $resource 如果要對 collection 做 custom action 會很難處理, 因為 $resource 不像 Rails 的 routes.rb 可以定義 collection 和 member action, 而且話說回來 Rails 的 router 處理 collection action 本來就是跟 id 多載, 所以我看到 Stack Overflow 上面有人的做法是這樣: // 以「把所有的噗都設為已讀」(MAAR) 為例 var Plurk = $resource("/plurks/:id:collectionAction/:memberAction", { id: "@id", collectionAction: "", memberAction: "" }, { maar: { method: "POST", params: { id: "", collectionAction: "maar" } } }); 這樣很醜,但似乎很多人都是這樣寫的,不過我實際上沒寫過就是了。 ※ 引述《lisaweng (piglet)》之銘言: : 最近在學AngularJs 不知道各位大大有沒有學過 : 後端是用rails寫的 : 面臨到的問題是 : 一開始view那邊我都是用angularJs從rails拿data : 把.JSON的資料存到變數 : 然後再顯示在網頁上 : 可是發現這樣好像就沒怎麼到two way data binding : 所以請問這樣我在做的時候也是要在AngularJS建資料嗎 : 例如說假設我現在在做一個部落格 : 我現在的做法是 : 每當我在點"Create Article" 我的文章就會存在rails那邊 : 然後當我要顯示那個文章的時候。我必須去讀那個文章的.JSON : 可是這樣好像不太效率 : 是不是我應該要改成我每一次點Create Article的時候 : 要把資料同時存在rails和js呢? : 然後讀的時候可以直接從js讀? : 謝謝! -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.231.18.230 ※ 文章網址: http://www.ptt.cc/bbs/Web_Design/M.1397743476.A.7C2.html ※ 編輯: ducksteven (36.231.18.230), 04/17/2014 22:06:28 ※ 編輯: ducksteven (36.231.18.230), 04/17/2014 22:09:45 ※ 編輯: ducksteven (36.231.18.230), 04/17/2014 22:11:17 ※ 編輯: ducksteven (36.231.18.230), 04/17/2014 22:14:22 ※ 編輯: ducksteven (36.231.18.230), 04/17/2014 22:18:21
sdlong:Xdite: Rails 跟 AngularJS 是無法整合的,別白費力氣 XD 04/18 03:19
turtleknight:真多學問...還好我可以用websocket... 04/18 10:38
LetDogDay:為什麼不能整合? 04/19 20:07
Rplus:推 04/20 01:53
a83294:ember會不會比較好 04/21 15:28
lisaweng:一直忘記來推文 謝謝你噢 :D 04/29 21:38