Re: [问题] AngularJs 和 rails

楼主: ducksteven (鸭七‧林新)   2014-04-17 22:04:33
我最近在做 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读?
: 谢谢!
作者: sdlong (sdlong)   2014-04-18 03:19:00
Xdite: Rails 跟 AngularJS 是无法整合的,别白费力气 XD
作者: turtleknight (turtle)   2014-04-18 10:38:00
真多学问...还好我可以用websocket...
作者: LetDogDay (推动世界让狗日~~)   2014-04-19 20:07:00
为什么不能整合?
作者: Rplus (R+) (9527)   2014-04-20 01:53:00
作者: a83294 (马岱)   2014-04-21 15:28:00
ember会不会比较好
作者: lisaweng (piglet)   2014-04-29 21:38:00
一直忘记来推文 谢谢你噢 :D

Links booklink

Contact Us: admin [ a t ] ucptt.com