使用RailsAPI和Angular来尝试开发一个酷炫的网页应用【尝试调用API】
这是继《构建酷炫的Web应用(使用Rails API和Angular)——环境配置指南》之后的续篇。
上次的概要
创建一个Rails API应用
↓
使用Webpack打包Angular应用并放入/public目录下
↓
虽然是Rails API应用,但只返回根页面作为SPA
所以这一次我只是从Angular调用API而已。
没有什么太了不起的,所以可能会有点无聊。
在离开之前,请记得把文件存档起来。
我会准备源代码,供您参考。
创建API
执行脚手架命令。
$rails g scaffold User
由于是API模式,系统会自动判断并生成迁移、模型和控制器。太聪明了。
Running via Spring preloader in process 4795
invoke active_record
create db/migrate/20161001061821_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
invoke resource_route
route resources :users
invoke scaffold_controller
create app/controllers/users_controller.rb
invoke test_unit
create test/controllers/users_controller_test.rb
控制器已经成为API规范,所以我没有特别要做的事情了,好的。
class UsersController < ApplicationController
before_action :set_user, only: [:show, :update, :destroy]
# GET /users
def index
@users = User.all
render json: @users
end
# GET /users/1
def show
render json: @user
end
# POST /users
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created, location: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /users/1
def update
if @user.update(user_params)
render json: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end
# DELETE /users/1
def destroy
@user.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def user_params
params.fetch(:user, {})
end
end
由于创建一个仅作为示例的数据库也很麻烦,所以我决定在GET /users的接口中返回固定值。很抱歉给您带来麻烦。
def index
@users = []
(1..10).each{|i|
@users.push({id: i, name: 'ユーザー'<<i.to_s})
}
render json: @users
end
为了避免因迁移而受到指责,稍微调整一下配置。
config.active_record.migration_error = false
调用API
为了从Angular应用程序中调用RestAPI,您需要使用$resource工厂。在这种情况下,需要单独安装名为angular-resource的模块,但如果您正在使用上次提到的package.json,则应该已经安装了它。但是,请注意如果模块不同,那么类型定义文件也会不同,因此您需要安装它。
安装类型定义文件。
$cd app/angular/javascripts/
$dtsm install angularjs/angular-resource --save
我们定义了一个名为UserResource的资源,用于调用API。
mkdir resources
touch resources/user-resource.ts
/// <reference path="../typings/bundle.d.ts"/>
export interface User {
id: number
name: string
}
interface Resource extends ng.resource.IResource<User>, User {
}
export default class UserResource {
get userResource(): ng.resource.IResourceClass<Resource>{
return <ng.resource.IResourceClass<Resource>>this.resource('/users')
}
static $inject = ['$resource']
constructor(private resource: ng.resource.IResourceService) {
}
all(success: (v: Array<User>) => void) {
let res = this.userResource.query({
},
() => {
success(res)
})
}
}
angular.module('App').service('userResource', UserResource)
我们将定义一个组件,仅从资源中获取用户列表并进行显示。
mkdir components
touch components/users.ts
///<reference path="../typings/bundle.d.ts"/>
import angular = require('angular')
import UserResource from '../resources/user-resource'
import {User} from '../resources/user-resource'
class Users {
private users: Array<User>
static $inject = ['userResource']
constructor(private userResource: UserResource) {
this.userResource.all((users)=> {
this.users = users
})
}
}
angular.module('App').component('users', {
controller: Users,
bindings: {},
template:
`
<md-list>
<md-list-item ng-repeat="user in $ctrl.users">
<p> {{ user.name }} </p>
<md-checkbox class="md-secondary"></md-checkbox>
</md-list-item>
</md-list>
`
})
在应用程序的入口点appliaction.ts中,需要添加两个类进行require。
/// <reference path="./typings/bundle.d.ts"/>
// angular
import angular = require('angular')
require('angular-material')
require('angular-cookies')
require('angular-resource')
require('angular-sanitize')
require('angular-route')
require('angular-animate')
require('angular-material-icons')
require('es5-shim')
let app = angular.module('App', [
'ngMaterial',
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute',
'ngMdIcons',
'ngAnimate'
]);
//stylesheets
require('../stylesheets/application')
//components
require('./components/users')
//services
require('./resources/user-resource')
//angular-materialのTheme
app.config(($mdThemingProvider) => {
$mdThemingProvider.theme('default')
.primaryPalette('grey', {
'default': '100'
})
.accentPalette('pink', {
'default': '700'
});
});
//Controllerも一緒に定義しちゃいました
export default class AppCtrl {
private title: string = 'Hello RailsAPI × Angular!'
static $inject = ['$rootScope', '$scope', '$cookies', '$window', '$timeout', '$location', 'userResource']
constructor(
private rootScope: ng.IRootScopeService,
private scope: ng.IScope,
private cookies: any,
private window: ng.IWindowService,
private timeout: ng.ITimeoutService,
private location: ng.ILocationService
) {
}
}
app.controller('AppCtrl', AppCtrl)
然后尝试使用已经创建的组件。
<html ng-app="App">
<head>
<meta charset="UTF-8">
<meta name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1">
<title>rails-api-angular</title>
</head>
<body ng-controller="AppCtrl as appCtrl" ng-cloak>
<header class="header md-whiteframe-3dp">
<md-toolbar md-scroll-shrink>
<div class="md-toolbar-tools">
<h3>
<span>rails-api-angular</span>
</h3>
<span flex></span>
<md-button class="md-accent">Sign up</md-button>
<md-button class="md-accent">Log in</md-button>
</div>
</md-toolbar>
</header>
<div layout="column" layout-align="center center">
<h1>{{appCtrl.title}}</h1>
<!--component-->
<users></users>
</div>
<%= stylesheet_link_tag webpack_asset_path('application.css') %>
<%= javascript_include_tag webpack_asset_path('application.js')%>
</body>
</html>
运行Webpack和Rails
$npm run dev
$rails s
来了!因为寂寞所以加了复选框。
下次我想要讨论如何将Angular Material变得更加实用。