App MakerでCSVアップロード

どうもこんばんは、みかんです。

**！！！！とつぜんですがたいせつなおしらせ！！！！**

2020年1月27日
App Maker の提供終了に向けた対応のご案内
https://support.google.com/a/answer/9682494?p=am_announcement&visit_id=637157414793613981-426262357&rd=1


??!???!?!?!???!?

残念ながら2021年1月19日には終了してしまうそうです(涙)
移行先はAppSheetかApp EngineかGoogleフォームだそうです・・・

消すのは忍びないので記事は残して置きますが、何かの間違いじゃ無い限り役に立つことはないでしょう・・・


**！！！！おしらせはおわりです！！！！！**


App MakerでCSVをアップロードする方法を書いてみます。
下記ステップでやっていきます。

* モデルと画面の下準備
* DrivePickerをアップロード対応させる
* アップロードしたCSVを参照するコードを書く
* CSVをモデルに保存する処理を書く

モデルを使うのでCloud SQL設定済み推奨ですが、CSVアップロード自体に関しては特に必須では無いです。

# モデルと画像の下準備

|<img width="200" alt="ap01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/2c2253fa-9b18-af05-4817-a433f6bbdaab.png">|<img width="207" alt="ap02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/d5b02d1d-748e-f7ea-2325-3e967f2bcc46.png">|
|:---:|:---:|

Starter Appで開始。適当に名前をつけときます。

|<img width="230" alt="ap03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/e372080e-fc5f-077f-fd04-eb593a2692e8.png">|<img width="294" alt="ap04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/5f2ccd06-397d-b089-39ca-d0c559ac12c2.png">|<img width="99" alt="ap05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/a02ac2dc-93f5-983a-8070-6f4b2e329ea5.png">|
|:---:|:---:|:---:|


モデルを用意します。Cloud SQLにして名前をSampleにします。

|<img width="218" alt="ap06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/d5095bd8-999d-630a-67f4-067692c1d31f.png">|
|:-:|

フィールドはNameとAgeを追加。

|<img width="699" alt="ap07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/c926a924-d116-b1cd-60b7-819fd122b5da.png">|
|:-:|

画面をいじっていきます。Pageの余計な文字列を削除。

|<img width="107" alt="ap08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/b233c51f-95f9-bfc5-d606-80e93eb1822d.png">|<img width="500" alt="ap09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/7f70d544-87f4-5021-9f5e-2344792db0fe.png">|
|:---:|:---:|:---:|


Drive Pickerウィジェットを配置します。あとSampleモデルをバインドしたテーブルも。

# DrivePickerをアップロード対応させる
そのままだとDrivePickerのuploadタブは動作しないバグがあります。
これは権限が足りないせいです。DrivePickerを置いただけでは必要な権限を要求してくれません。
なので下記のようなダミーコードを、サーバースクリプトを作って書いておきます。
そのあとpreviewなりdeployすると、書き込み権限含めて権限要求が走ります。

```javascript
 //関数も適当でおk
 function serverSayHello() {
  DriveApp.addFile();
}
```

必須では無いですが、ちょっと細工します。
今回はアップロード目的なので、ファイルを選択するタブは不要です。
それが表示されないようにプロパティをいじります。

|![ap10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/76b5e694-4621-5390-5408-ebbbba4602f4.png)|
|:-:|

DOCSがついてます。

|![ap11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/cb9f1194-3d12-96e0-8300-9ed0607d934a.png)|
|:-:|

クリックしたあと、DOCSの横のゴミ箱アイコン押してDone。

|![ap12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/e65eaaf6-c7e4-a0e6-3f34-26708a139bc4.png)|
|:-:|

空っぽになりました。

# アップロードしたCSVを参照するコードを書く
アップロードが完了したタイミングで、DrivePickerウィジェットのonDocumentSelect関数が呼び出されます。

|![ap13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/9ce4fde6-ddd8-2491-36ae-fc3ff083d6a8.png)|
|:-:|

こんな感じで、適当な関数名を書いておきましょう。実際の関数はSCRIPTSのクライアントスクリプトに書きます。

```javascript
function onSelected(response) {
  google.script.run
   .withSuccessHandler(function(){
   app.datasources.Sample.load();
  })
   .onSelectedInServer(response);
}
```

こんなふうに。サーバースクリプト側でCSVデータをモデルに格納する予定ですが、それが終わったら画面側ではデータを読み直して欲しいので、withSuccessHandlerにはSampleモデルのload関数呼び出しを書いています。

```javascript
function onSelectedInServer(response) {
  var docInfo = response.docs[0];
  var id = docInfo.id;
  
  var file = DriveApp.getFileById(id);
  var csv = Utilities.parseCsv(file.getBlob().getDataAsString());
```

続けてサーバースクリプトです。responseはjsonなので、必要なプロパティをガンガン参照。
アップロードしたファイルはGoogle Driveのマイドライブに保存されています。
そのファイルのIDもresponseに入っているので、それをDriveAppのgetFileById関数に食わせます。
あとは便利な関数たちを使って、CSVデータ(二次元配列)を手に入れます。

ちなみにresponse jsonの定義は
https://developers.google.com/picker/docs/results?hl=ja
にあります。

# CSVをモデルに保存する処理を書く


```javascript
  var records = [];
  var isHeader = true;
  csv.forEach(function(row){
    if (isHeader) {
      isHeader = false;
      return;
    }
    var record = app.models.Sample.newRecord();
    record.Name = row[0];
    record.Age = Number(row[1]);
    records.push(record);
  });
  app.saveRecords(records);
}
```

先程のサーバースクリプトの下半分です。
サーバースクリプトで、App Makerのモデルにデータを追加するには、app.modelsから指定のモデルのnewRecord関数を呼び、それで得られるrecordオブジェクトをapp.saveRecords関数に入れるという形で記述します。

# 動作確認
ここまで書いてPreviewで実行すると、CSVアップロード→テーブルに追加されたデータが表示される、という動きが確認できます。

CSVは

|![ap17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/3f62b616-27da-58fc-58cf-a9025955c804.png)|
|:-:|

みたいな感じです。

|![preview-compressor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26085/0cfb86a5-5462-65f0-33ee-751a6e5499ae.gif)|
|:-:|

実行イメージはこんな感じ。

以上です。良いApp Makerライフを!