GASを使っていい感じの応募フォームを作った話
この記事はGoogle Apps Script Advent Calendar 201816日目の記事です。
ちょうど去年の今頃に、ある団体でオリジナルトレーナーを作ろうという話が持ち上がりました。
団体規模は3桁、日本各地にいるという状態だったのでどのような流れでトレーナーを届けるか色々思案しました。
そのときにちょうどGASというものを知ったので、Google FormとSpreadSheetsとGASを使って注文フォームを作りました。
その時のコードを知見として紹介できたらなと思います。
また、記事を書くにあたって現代の文法にリメイク(リファクタリング?)しました。
全体の流れ
当時は以下のような流れで注文者のもとにトレーナーを届けていました。
今回は主に赤丸の部分について説明していきます。
環境構築
なるべく今風に書くにあたって、ES6以上の構文を使ってローカルで組めるようにしました。
ローカルでGASを組む
ローカルでGASを組みには、claspというGoogle製のツールを使います。
claspについては7日目のmatsuoshi氏や、9日目のtakanakahiko氏が記事として取り上げていらっしゃるので、詳細は割愛させていただきます。
ES6以上の構文でGASを組む
両氏ともTypeScriptを用いて組まれていらっしゃるのですが、私はTypeScriptを書いたことがないのでBabelを利用してJavaScriptで書いています。
結構ゴリ押しなのですが、まずはBabelをインストールして(Babel7から名前が babel-
から @babel/
に変わってます。)
yarn add -D @babel/core @babel/cli
PresetとPluginを入れます。
yarn add -D @babel/preset-env babel-plugin-transform-member-expression-literals babel-plugin-transform-property-literals
PresetとPluginはこちらを参考にしました。(何故か配布されているやつをインストールしても使えなかった…)
あとは .babelrc
に記述して
{
"presets": ["@babel/preset-env"],
"plugins": ["transform-property-literals", "transform-member-expression-literals"]
}
npm scriptsを設定すれば完了です。
"scripts": {
"build": "npx babel src/*.js --out-dir build"
}
この設定をしておけば、 npm run build
をした後 ./dist
下で clasp push
をすればOKです。
ひとつ注意点ですが、 clasp push
をするディレクトリに appsscript.json
を置かなくてはいけません。(ここでちょっとハマった)
Formを準備する
今回必要な情報は
- メールアドレス
- 名前
- フリガナ
- 郵便番号
- 住所
- トレーナーのサイズ
です。
Formはただ質問を準備するだけなので、特に説明はしません。
今回は以下のように準備しました。
郵便番号は正規表現を用いてフォーマットを固定しています。([0-9]{3}-[\d]{4}
)
氏名やフリガナが姓と名で分かれているのは、入力者による入力フォーマットの差を無くすためです。
実際に書いたコード
以下のコードはES6以降の構文を用いたものです。FormからのResponseが保存されているシートの名前は Original
、整形してリスト化したものを保存するシートの名前が Roster
です。原則として Original
のデータは触りません。何か変更があった場合は必ず Roster
のデータをいじります。(何か起こったときに修復できるように)
const reservation = () => {
// FormからのResponseが保存されるSheetを取得
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Original");
reservationWithIndex(sheet.getLastRow(), sheet);
}
const reservationWithIndex = (index, sheet) => {
const info = sheet.getRange(index, 1, 1, sheet.getLastColumn()).getValues()[0];
const name = `${info[2]} ${info[3]}`; // 名前
const ruby = `${info[4]} ${info[5]}`; // ふりがな
const addressCode = info[6]; // 郵便番号
const address = info[7] + info[8]; // 住所
const size = info[9]; // サイズ
const message = "メール本文";
try {
// MailApp.sendEmail(送信先メールアドレス, メールタイトル, メール本文)
MailApp.sendEmail(info[1],"{メールタイトル}", message);
} catch(e) {
// エラーが出たときは自分のメールにエラー内容を送る
MailApp.sendEmail("hogehoge@blog.oldbigbuddha.net", e.message, e.message);
}
// 別シートに情報を写す関数(自作)
makeList(info);
}
// サイズの値段を計算
const calcPrice = size => {
if ( size === "XS" ) return "4,100"; // XSのとき
else if ( size === "XXL" ) return "5,000"; // S,M,Lのとき
else return "4,500"; // XLのとき
}
const makeList = info => {
// 書き込み先のSheetを取得
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Roster");
const name = `${info[2]} ${info[3]}`; // 氏名
const ruby = `${info[4]} ${info[5]}`; // ふりがな
const addressCode = info[6]; // 郵便番号
const address = info[7] + info[8]; // 住所
const size = info[9]; // サイズ
var info = [ [
info[0], // メールアドレス
size,
name,
ruby,
addressCode,
address
] ];
// 最終行に新規注文者を追加
sheet.getRange(sheet.getLastRow() + 1, 1, 1, 6).setValues(info);
}
reservation
の実行TriggerをFormからResponseが来たときに設定しておきます。getLastRow()
の値がその得た情報のIndexを示しています。
reservationWithIndex
と reservation
をわけることによって、何か情報を修正したりメールを再送信する必要ができたときに即席のfix関数を用意できるようにしています。
締め
コード各所にコメントを入れているので、特にコードに関する説明はしませんでした。
もしここの処理なにやってるのかわからんとか、ここはこう書いたほうがいいよっていうのがありましたら @OldBigBuddha までお願いします。DMは閉じていますのでリプライかメンションでお願いします。ローカルで組めたり、今どきの構文で書けたりとGASもなかなか進化しましたね。最近はG Suite DeveloperHubが追加されたりとGASの環境が整いつつありますので、ぜひ皆さんご活用されてみてはと思います。(カレンダー経由で来た方はすでにフル活用されていることと思いますがw)
ありがとうございました。