1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GASでGoogleフォームの選択肢を自動更新したら「マスタ管理」の壁にぶつかった話

1
Last updated at Posted at 2026-04-19

この記事を読んだほうが良い人

  • 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_IDYOUR_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 公式サイトからお気軽にどうぞ。


※ この記事は DRASENAS Blog の転載です。オリジナルではコードや設定手順が随時アップデートされています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?