最近本来是在折腾 parse angular rails 的一个项目。一直想把 parse 封装成和 rails 自带的 activerecord 那样的的 api 但是最终由于各种原因还是放弃了。整体来说还是因为 parse 的社区不够大,需求量不够大,导致周边做的不是很给力。要啥啥没有也就罢了,关键是 parse 目前处于高不成低不就的地步:要啥有啥,但是,做的不好,不完善。
浪费了一天在 parse-resource
上无果很是伤心。总想做点东西去弥补下损失,起码找到个可以用于目前项目的,简化项目开发的东西吧?那就从这个的周边入手吧。我一直都在想如果 backend restful 的这个接口搞定了,那前面就可以尝试 angular-resource
了。虽说目前后端没有搞定,但是我们依然可以去尝试它。
angular-resource
就是一个可以简化 angular
写 restful 接口的工具。之前不使用它是因为有这样一个疑问:我并不是仅仅有 restful CRUD 的接口。当我有其他的自定义的动作的时候 angular-resource
能支持吗?今天我终于把这个问题弄清楚了。
首先,要给 angular-resource
提供一个完整的 restful 的 backend。这里我就用 rails 做了一个。
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
respond_with @posts
end
def show
@post = Post.find_by_id(params[:id])
respond_with @post, status: if @post.nil? then :not_found else 200 end
end
def create
@post = Post.new(params[:post])
@post.save
respond_with @post
end
def update
@post = Post.find_by_id(params[:id])
@post.update_attributes(params[:post]) if @post
respond_with @post, status: if @post.nil? then :not_found else 200 end
end
def destroy
@post = Post.find_by_id(params[:id])
@post.destroy if @post
respond_with @post, status: if @post.nil? then :not_found else 200 end
end
def reset
@post = Post.find_by_id(params[:id])
if @post
@post.body = 'reset as default content'
@post.save
end
respond_with @post, status: if @post.nil? then :not_found else 200 end
end
def top2
@posts = Post.limit(2)
respond_with @posts
end
end
这个 controller 在错误的处理以及 http code 的返回上可能还有一些问题,但是我们先忽略这些。关键的提供一个如下的 routes。
resources :posts do
member do
post :reset
end
collection do
get :top2
end
end
$: rake routes
reset_post POST /posts/:id/reset(.:format) posts#reset
top2_posts GET /posts/top2(.:format) posts#top2
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
好,有了这些之后,我们就可以用 angular-resource
构建一个 Post
的 module 来处理 restful 的请求啦。
首先 ngResource 的文档在这里 https://docs.angularjs.org/api/ngResource.$resource 虽然大家都吐槽 angular 的文档很糟糕,但是没有别的办法,这个就是最官方的出处了。而且起码我觉得这篇讲的还算说的过去。
App = angular.module 'App', ['ngResource']
App.factory 'Post', ($resource) ->
$resource('/posts/:id/:verb', {id: '@id'},
reset: { method: 'POST', params: {verb: 'reset'} }
top2: { method: 'GET', params: {verb: 'top2'}, isArray: true }
)
如上所示,对于有自定义的 restful 接口的情况,我提供了一个额外的参数 verb
。对默认的 restful 接口 angular-resource
可以帮我们处理了,我们只需要处理额外的自定义的即可。
reset: { method: 'POST', params: {verb: 'reset'} }
设置 verb: reset 就可以将这个动作和 url 绑定了。
post = new Post($scope.post)
post.$reset(
(data) ->
alert('success!!')
$scope.post = data
)
同理,
top2: { method: 'GET', params: {verb: 'top2'}, isArray: true }
verb: top2 就对应 posts/top2 的 url。不过这里有一个额外的参数 isArray
这个就好像 rails routes 里面声明的 collection
一样,说明不是针对单个元素的。
App.controller 'IndexController', ($scope, Post) ->
$scope.posts = Post.top2()
虽然这里还没有涉及嵌套的情况,但是整体来说应该是类似的。
顺便说一句,项目用到了一个 gem bower-rails
把 bower 整合进来。可以更简单的安装 各种 css js 资源。https://pete-hamilton.co.uk/2013/07/13/angularjs-and-rails-with-bower/ 的讲解推荐一看。
再多说一句,前面有一篇讲述 webapps 的文章,这篇其实和它也有一点关系。目前我比较看好 angularjs 希望用它作为 webapp 的开发框架。