この記事を読んだほうが良い人
- Googleフォームの選択肢(担当者名・部署名など)を毎回手動で更新していて面倒を感じている人
- GASでフォームを動的更新する仕組みを作ったものの、うまく機能しなくて困っている人
- 「自動化した=運用コストゼロ」と思い込んでいて痛い目を見たことがある人 フォームの選択肢を手動で更新するのが、じわじわとストレスになっていませんか。
担当者が変わるたびにフォームを開いて、選択肢を追加して、古い名前を消して……。月に数回ならまだしも、組織の変化が多い時期だと週に何度もその作業が発生します。この記事では、GASを使ってGoogleスプレッドシートのマスタからフォームの選択肢を自動で同期する仕組みを作った経験と、その過程で直面した「マスタ管理」の問題をそのまま書きます。
背景
社内の問い合わせ受付用Googleフォームで、担当者ごとの振り分けをフォームの選択肢で実現していました。担当者は十数名、月1〜2回のペースで入れ替わりがある環境です。フォームの更新漏れによる「存在しない担当者に問い合わせが飛ぶ」事故が複数回発生したため、スプレッドシートのマスタと連動させる自動化に踏み切りました。
やったこと
スプレッドシートの構成
マスタシートはシンプルにしました。担当者マスタ というシート名で、A列に氏名を縦に並べるだけです。
| A列 |
|---|
| 担当者名(ヘッダー) |
| 田中 太郎 |
| 鈴木 花子 |
| … |
B列以降に部署やメールアドレスを持たせることもできますが、フォームの選択肢に必要なのは名前だけなので、最初はA列だけで動かしました。なお後述しますが、運用改善の過程でB1セルに「最終更新日」を入れるルールを追加しています。マスタの鮮度チェックに使うためです。
GASのコード
フォームの特定の質問(ListItem)の選択肢を、スプレッドシートの内容で上書きするスクリプトです。スクリプトエディタで新しいファイルを作り、以下をそのまま貼り付けます。
// スプレッドシートのマスタシートを読み取り、フォームの選択肢を更新する
function updateFormChoices() {
const SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID'; // マスタシートのスプレッドシートID
const SHEET_NAME = '担当者マスタ';
const FORM_ID = 'YOUR_FORM_ID'; // 対象フォームのID
const QUESTION_TITLE = '担当者を選択してください'; // フォーム上の質問文と完全一致させる
// マスタから担当者名を取得(空白行を除外)
const sheet = SpreadsheetApp
.openById(SPREADSHEET_ID)
.getSheetByName(SHEET_NAME);
const values = sheet
.getRange('A2:A') // 1行目はヘッダーなのでA2から取得
.getValues()
.flat()
.filter(v => v !== '');
if (values.length === 0) {
console.error('マスタに担当者が1件もいません。処理を中断します。');
return;
}
// フォームの対象質問を探して選択肢を更新
const form = FormApp.openById(FORM_ID);
const items = form.getItems(FormApp.ItemType.LIST_ITEM); // リスト形式の質問のみ対象
let updated = false;
items.forEach(item => {
if (item.getTitle() === QUESTION_TITLE) {
item.asListItem().setChoiceValues(values);
updated = true;
console.log(`更新完了: ${values.length}件の選択肢をセットしました`);
}
});
if (!updated) {
console.warn(`質問「${QUESTION_TITLE}」が見つかりませんでした。質問文を確認してください。`);
}
}
YOUR_SPREADSHEET_ID と YOUR_FORM_ID の2箇所を置き換えるだけで動きます。スプレッドシートのIDはURLの /d/ と /edit の間の文字列、フォームのIDは同様に /d/ と /edit の間です。
QUESTION_TITLE はフォーム上の質問文と完全一致させてください。スペースの全角/半角の違いでマッチしないことがあります。
トリガーの設定
スクリプトエディタの「トリガー」から時間駆動トリガーを設定します。担当者の変更頻度に合わせますが、毎日1回(深夜0時〜1時)で十分でした。
スプレッドシート側に onEdit トリガーを仕掛けて、マスタを編集した瞬間に同期する方法もあります。ただし、編集途中(セルに入力中)でもトリガーが走るため、中途半端な状態でフォームが更新されるリスクがあります。日次バッチの方が安定します。
ハマったポイント
マスタが更新されていないとシステムが静かに壊れる
スクリプト自体は問題なく動いていました。毎朝きちんとフォームの選択肢を更新しています。ところが、実際の運用で「退職した担当者が選択肢に残っている」「新しい担当者が出てこない」という報告が続きました。
原因を追ったら、マスタシートが更新されていなかっただけです。
GASはスプレッドシートの内容をそのままフォームに反映するので、元のデータが間違っていれば間違ったまま同期します。エラーもアラートも出ません。updateFormChoices() のログには「5件の選択肢をセットしました」と正常終了のメッセージが残っています。システムとしては完全に正常動作です。
自動化したことで「フォームは自動で正しくなる」という誤解が生まれ、マスタの更新を誰もしなくなっていました。仕組みが裏で動いているのが見えないからこそ、ケアが抜けやすい。これが一番の誤算でした。
「誰がマスタを更新するか」が決まっていなかった
担当者の入れ替えは人事関連の話なので、情報は管理部門が持っています。ただ、スプレッドシートの更新は「システム担当っぽい人」がやるものだという空気があり、実際には誰も責任を持っていませんでした。
ツールの問題ではなく、オーナーシップの問題です。自動化する前は「フォームを更新する人=フォームのオーナー」が明確でした。GASを挟んだことで責任の所在が曖昧になりました。
結果と学び
対策として2つやりました。
1. マスタに「最終更新日」列と更新者名を追加する
B列に更新日(=TODAY() を手動で確定入力)、C列に更新者名を記入するルールにしました。スクリプト側でこの日付をチェックし、30日以上古ければSlackに警告を飛ばす処理を追加しています。
// マスタの最終更新日をチェックし、30日以上経過していたら警告を送る
function checkMasterFreshness() {
const SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID';
const SHEET_NAME = '担当者マスタ';
const SLACK_WEBHOOK_URL = 'YOUR_SLACK_WEBHOOK_URL';
const THRESHOLD_DAYS = 30;
const sheet = SpreadsheetApp
.openById(SPREADSHEET_ID)
.getSheetByName(SHEET_NAME);
// B1セルに最終更新日を入れる運用にしている
const lastUpdated = sheet.getRange('B1').getValue();
if (!(lastUpdated instanceof Date)) {
notifySlack(SLACK_WEBHOOK_URL, '⚠️ 担当者マスタの最終更新日が未設定です。確認してください。');
return;
}
const daysSinceUpdate = Math.floor(
(new Date() - lastUpdated) / (1000 * 60 * 60 * 24)
);
if (daysSinceUpdate >= THRESHOLD_DAYS) {
notifySlack(
SLACK_WEBHOOK_URL,
`⚠️ 担当者マスタが${daysSinceUpdate}日間更新されていません。内容を確認してください。`
);
}
}
function notifySlack(webhookUrl, message) {
const payload = JSON.stringify({ text: message });
UrlFetchApp.fetch(webhookUrl, {
method: 'POST',
contentType: 'application/json',
payload: payload,
});
}
checkMasterFreshness() は週次(月曜朝9時)で動かしています。警告が来たらマスタを確認する、という習慣が定着しました。
2. マスタの更新オーナーを明示的に決める
管理部門の特定の担当者に「このシートはあなたが管理する」とはっきり伝え、スプレッドシートの共有設定でもその人を編集権限の筆頭に置きました。Slackの警告通知もその人のDMに直接送るようにしています。
自動化は手間を減らしますが、「インプットの正しさを担保する責任」は人間が持ち続けます。GASが毎日完璧に動いていても、食わせるデータが古ければ出力も古い。当たり前のことですが、仕組みが見えにくくなると意識から抜け落ちやすい。
Googleフォームの動的更新を実装する場合、コードと同じくらい「マスタの更新フロー設計」に時間を使うことをお勧めします。コードは1時間で書けますが、運用の合意形成は1週間かかることもあります。
コーポレートITのご相談はお気軽に
この記事で書いたような業務改善・自動化の設計から実装まで、DRASENASではコーポレートITの現場に寄り添った支援を行っています。 「まず相談だけ」でも大歓迎です。DRASENAS 公式サイトからお気軽にどうぞ。
御社の IT 部門、ここにあります。
「ITのことはあまりわからない」── そのような状態からで、まったく問題ございません。まずはお気軽にご相談ください。