Ionic + Railsのサンプルアプリ（ng-token-auth+devise_token_authを使った認証）


## What's Ionic ?
- Ionicは、HTML5を用いたハイブリッドモバイルアプリケーションを構築するためのオープンソースのフロントエンドSDK
- Ionicには、レスポンシブフレームワークとは異なり、iOSやAndoridのネイティブSDKで得られるようなモバイルUIとレイアウトが含まれている

### ハイブリッドアプリ
- ハイブリッドアプリは、アプリの中のブラウザシェルで実行されていて、ネイティブのプラットフォーム層にアクセスすることもできる、小型のウェブサイト
- ハイブリッドアプリは、特にプラットフォームのサポート、開発のスピード、およびサードパーティ製のコードの利用面で、純粋なネイティブアプリケーションと比べて多くの利点を持っている

## Ionicの特徴
- Apache Cordovaを拡張して作られている、モバイルUIフレームワーク＆開発ツール
- AngularJSやSassを採用している

## Ionic開発環境の構築
- ここでは、```generator-ionic```を用いて、Ionic開発環境を構築します

```bash
$npm install -g generator-ionic
```

- ```yo ionic```でプロジェクトのひな形を作成します。プロジェクトフォルダを作成後、そのフォルダ内でコマンドを実行します

```bash
$ mkdir my-ionic-project && cd $_
$ yo ionic
```

### ブラウザで起動する

```bash
$grunt serve
```

### プラットフォームを追加する

```bash
$grunt platform:add:ios
$grunt platform:add:android
```

### エミュレーターで動かす

```bash
$grunt emulate:ios --livereload
```

[diegonetto/generator-ionic](https://github.com/diegonetto/generator-ionic)

## Token認証
- ng-token-authとdevise_token_authを用いて、Token認証を実装することを考えます

### サーバーサイド
- サーバーサイドはなんでも良いですが、ここではRailsで、devise_token_authを採用します
- サーバーサイドの実装については、別の記事でも書きましたので、こちらをご参考にいただければと思います

[AngularJSとRailsをTokenベースの認証で繋ぐ方法(devise_token_auth + ng-token-auth) - Qiita](http://qiita.com/jwako/items/d9f966a5edca1b07c393)

- サンプルコードもgithubにおいてあります

[jwako/devise_token_auth_demo](https://github.com/jwako/devise_token_auth_demo)

## AngularJS in Ionic
- AngularJSを触ったことがあれば、通常のAngularJSプロジェクトと同様にアプリケーションを構築していくことができます

### 使用するモジュールの指定
- ```bower.json```にng-token-authとangular-resourceを追加、インストールします

```bower.json
{
  "name": "IonicRailsSample",
  "version": "0.0.0",
  "dependencies": {
    "ionic": "v1.0.0-beta.14",
    "ngCordova": "0.1.12-alpha",
    "ng-token-auth": "latest",
    "angular-resource": "latest"
  },
  "devDependencies": {
    "angular-mocks": "~1.3.6",
    "angular-scenario": "~1.3.6"
  },
  "resolutions": {
    "angular": "1.3.6"
  }
}
```

- ```app.js```で使用するモジュールを注入してやります

```app/scripts/app.js
angular.module('sample', ['ionic', 
  'config',
  'sample.auth',
  'sample.home',
  'ng-token-auth',
  'ngResource'])
...
```

### router
- ルーティングは、```ui.router```を用いて行います

```app/scripts/app.js
.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider

  .state('app', {
    url: "/app",
    abstract: true,
    templateUrl: "templates/menu.html",
    controller: 'AuthCtrl'
  })

  .state('app.top', {
    url: "/top",
    views: {
      'menuContent': {
        templateUrl: "templates/top.html"
      }
    }
  })

  .state('app.home', {
    url: "/home",
    views: {
      'menuContent': {
        templateUrl: "templates/home.html",
        controller: 'HomeCtrl'
      }
    }
  });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/top');
});
```

### ng-token-auth
- ng-token-authは、AngularJSでToken認証を実現するためのライブラリです
- ng-token-authの設定は、以下のように設定できます

```app/scripts/app.js
.config(function($authProvider, ENV) {
  $authProvider.configure({
    apiUrl: ENV.apiEndpoint
  });
})
```

### View Templates
- Ionicは、cssフレームワークとJSライブラリの両方を提供してくれます
- モーダルは```ion-modal-view```タグ、リストは```ion-list```など多くのコンポーネントが用意されています
- 詳細は、以下を参考にしてください

[Javascript - Extend Ionic even further with the power of AngularJS - Ionic Framework](http://ionicframework.com/docs/api/)

- これらのコンポーネントを活用しながら、app/templates以下にHTMLファイルを作成していきます
- ログイン画面はこんな感じで、Emailとパスワードを入力後、Log inボタンを押下すると```doLogin()```を実行します

```app/templates/login.html
<ion-modal-view>
  <ion-header-bar>
    <h1 class="title">Login</h1>
    <div class="buttons">
      <button class="button button-clear" ng-click="closeLogin()">Close</button>
    </div>
  </ion-header-bar>
  <ion-content>
    <form ng-submit="doLogin()">
      <div class="list">
        <label class="item item-input">
          <span class="input-label">Email</span>
          <input type="text" ng-model="loginData.email">
        </label>
        <label class="item item-input">
          <span class="input-label">Password</span>
          <input type="password" ng-model="loginData.password">
        </label>
        <label class="item">
          <button class="button button-block button-positive" type="submit">Log in</button>
        </label>
      </div>
    </form>
  </ion-content>
</ion-modal-view>
```

### Controllers
- ng-token-authの```$auth.submitLogin()```で、サーバーサイドにSign inのリクエストをします

```app/scripts/auth.js
angular.module('sample.auth', [])

.controller('AuthCtrl', function($scope, $ionicModal, $timeout, $state, $auth) {
  // Form data for the login modal
  $scope.loginData = {};

  // Create the login modal that we will use later
  $ionicModal.fromTemplateUrl('templates/login.html', {
    scope: $scope
  }).then(function(modal) {
    $scope.modal = modal;
  });

  // Triggered in the login modal to close it
  $scope.closeLogin = function() {
    $scope.modal.hide();
  };

  // Open the login modal
  $scope.login = function() {
    $scope.modal.show();
  };

  // Perform the login action when the user submits the login form
  $scope.doLogin = function() {
    $auth.submitLogin($scope.loginData)
      .then(function(resp) { 
        $scope.closeLogin();
        $state.go('app.home');
      })
      .catch(function(resp) { 
        console.log(resp);
      });
  };
});
```

#### アクセス制限されたリソースへのアクセス
- ng-auth-tokenは、認証後の全てのリクエストをインターセプトしてAuthヘッダーを付加するので、Token周りの処理は全く記述する必要がありません

```app/scripts/home.js
angular.module('sample.home', [])

.controller('HomeCtrl', function($scope, User) {
  this.userService = new User(serverErrorHandler);
  this.userService.all().$promise.then(function(result) {
    return $scope.users = result.users;
  });

  var serverErrorHandler = function() {
    return console.log("There was a server error.");
  };
});
```

- factoryを作成し、$resourceでサーバーサイドのリソースにアクセスします

```app/scripts/user_services.js
angular.module('sample').factory('User', ['$resource', 'ENV', function($resource, ENV) {
    var User;
    return User = (function() {
      function User(errorHandler) {
        this.service = $resource(ENV.apiEndpoint + '/users.json', {}, {
          'query': {
            method: 'GET'
          }
        });
        this.errorHandler = errorHandler;
      }

      User.prototype.all = function() {
        return this.service.query((function() {
          return null;
        }), this.errorHandler);
      };

      return User;

    })();
  }
]);
```

## Ionicサンプルアプリ
- 作成したアプリは、以下にあります

[jwako/ionic_rails_sample](https://github.com/jwako/ionic_rails_sample)

- これと連携できるサーバーサイドのRailsアプリも作成しましたので、ローカルで試してみてください

[jwako/devise_token_auth_demo](https://github.com/jwako/devise_token_auth_demo)

## Ref.

[Ionic: Advanced HTML5 Hybrid Mobile App Framework](http://ionicframework.com/)

[JavaScript - [翻訳] Ionicガイド(1/5) - Qiita](http://qiita.com/icb54615/items/3f4c4916cf34870ec4ed)

[JavaScript - ionic（AngularJSベース）のアプリケーション開発環境を構築 - Qiita](http://qiita.com/hkusu/items/a9d5908ede11110acb88)

[ccoenraets/ioconf](https://github.com/ccoenraets/ioconf)