【やらかし記】回答が溜まったGoogleフォームをトリガ付きのスプレッドシートに紐づけたら、トリガが暴発した💥

# はじめに
世の中は「まぜるな危険」で溢れている。

今日、Googleフォームと、トリガ付きスプレッドシートを混ぜたら、爆発しました。💣💥

# 要約
Googleフォームの「回答の送信先を選択」で、「フォーム送信時」のトリガ付きのスプレッドシートを紐付けると、スプレッドシートの処理が回答の数だけ走ります。[^1]

[^1]:この記事は2025年3月17日時点の動作を元にしています。今後、挙動が変わることがあります。（変わってほしい）

# 顛末
## 登場するもの
- Googleフォーム
- 旧スプレッドシート
  - フォーム送信時にメールを送るGoogle Apps Script付き
- 新スプレッドシート
  - 旧スプレッドシートからプロジェクトを移植 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/664aed31-ece5-4ca4-9676-dba34ba8d25b.png)


## したこと 
Googleフォームに紐づいていた旧スプレッドシートを新スプレッドシートに引っ越ししようとした。回答が溜まり、列も乱れていたため。

- 旧スプレッドシートをコピー、新スプレッドシートを作成
- 新スプレッドシートにApps Scriptおよびトリガーをセットアップ。（⚠️これが火種）
- Googleフォームを新スプレッドシートに紐付け
- 溜まっていた回答の数だけ、トリガが発火💥

先にトリガーを設定したのが、将棋で言うところの手順前後でした。

# 再現手順（Step to Reproduce）
## 1. 適当なGoogleフォームを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/5c15d13f-6645-49ac-b801-d74c7eb91b73.png)

## 2. 回答を溜める

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/9b6e4e10-230b-4c8f-9786-48f7d886a55e.png)

## 3. スプレッドシートを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/7bf3716f-3f35-4d43-83e0-c5219bd57616.png)

## 4. Apps Scriptを作成
以下のように、フォーム提出時の処理とトリガー作成関数を追加。

```js
function onFormSubmit(e) {
  console.warn("Adieu, World!")
}

function setTrigger() {
  ScriptApp
    .newTrigger("onFormSubmit")
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onFormSubmit()
    .create()
}
```

## 5. トリガを実装
`setTrigger`を実行。以下のようにトリガが生成される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/3adab152-5913-4cb9-8d6d-c001a80b556a.png)

## 6. フォームをシートに紐付け
Googleフォームに戻り、シートを紐付け。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/58339c8b-881c-4621-b1ff-2367da1e5306.png)

「既存のスプレッドシートを選択」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/e95e0ec8-8786-460b-9091-f80400116fe6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/6552e05b-14bb-4585-baa0-ed7a016a4469.png)

紐付けされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/29aa7f44-7b43-4a53-b0d9-e1e3ab597162.png)

## 7. Apps Scriptを確認
ここでApps Scriptの実行ログを確認します...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/e70b1027-c1b3-4276-867f-390d3d6668b7.png)

回答分の3回、トリガ処理が走っています☺️

「フォーム送信時」とは...

# これは仕様...?
個人的にはこれは予期しない動きだったのですが、仕様なのでしょうか。

>インストール可能なフォーム送信トリガーは、ユーザーがフォームに回答したときに実行されます。フォーム送信トリガーには、Google フォーム自体用と、フォームがスプレッドシートに送信される場合のスプレッドシート用の 2 つのバージョンがあります。

https://developers.google.com/apps-script/guides/triggers/installable?hl=ja#event-driven_triggers

`フォームがスプレッドシートに送信される場合`に「**回答の送信先を選択**」したことが当てはまるかというと、まぁ当てはまらないとも言えないか...

内部実装に想いを馳せると、回答時にフォームからスプレッドシートに回答を送るのも、既存の回答を新規スプレッドシートに送るのも一緒！、と、おもんぱかることもできそうです。いや、おもんぱかれないでしょ。アルパカ🦙🦙🦙

Stackoverflowも探しましたが、関連情報はありませんでした。

# おわりに
筆者のケースでは実行数Quotaのおかげで途中からエラーになりましたが、それなりの物的・心的な被害を被りました。

Googleフォームの紐付け先を変える際は、

- 引っ越し前にフォームの回答をアーカイブ、回答を消しておく
- スプレッドシートのトリガーはフォームを紐づけてから付ける

のどちらかをしておくのが安心です。

と、ここに他山の石を残し、擱筆とします。

# おまけ：生成AIの意見
**gpt-4o + Web Search**
発火しない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/714d1dd5-0e48-4c4a-93cb-3fd4e297d2fe.png)


**Claude 3.7 Sonnet**
発火しない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/7af4886f-d538-46b7-8097-b0d2ccab8eb0.png)

**Gemini 2.0 Pro**
~~発火しない~~ 訂正：Geminiは正解でした。お家芸。「2. スプレッドシートの再リンク」が今回の事例ですね。回答の冒頭と矛盾している気もする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/3a4418cb-a9c1-4fb4-a157-4f930b0580c1.png)