使用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

来了!因为寂寞所以加了复选框。

Kobito.78ye0L.png

下次我想要讨论如何将Angular Material变得更加实用。

广告
将在 10 秒后关闭
bannerAds