フォームをGETで送信するときは送信したいパラメータをURLではなくhiddenタグに設定する必要がある、という話

# はじめに：イントロダクション

以下のような単純なRailsのフォームがあったとします。

```erb
<%= form_tag foo_blogs_path(some_flag: 1) do %>
  <%= button_tag 'Foo' %>
<% end %>
```

コントローラのコードは次のように`some_flag`の値をnoticeに出力するようになっています。

```ruby
class BlogsController < ApplicationController
  def foo
    redirect_to :blogs, notice: "Foo / some_flag: #{params[:some_flag]}"
  end
end
```

以下はFooボタンをクリックしたときの実行結果です。
フォームのURLに設定した`some_flag: 1`の値が表示されています。

<img width="159" alt="Screen Shot 2020-05-20 at 9.27.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/a89c9813-f478-eb6d-5a35-ca2e0aed0e54.png">

## 本題：困ったこと

上の例と同じようなことを以下のようなフォームでもやろうとしました。

```erb
<%= form_tag bar_blogs_path(some_flag: 1), method: :get do %>
  <%= button_tag 'Bar' %>
<% end %>
```

先ほどのコード例と違うのはフォームのHTTPメソッドがGETになっている点（`method: :get`）です。

コントローラ側のコードはほぼ同じです。

```ruby
class BlogsController < ApplicationController
  def bar
    redirect_to :blogs, notice: "Bar / some_flag: #{params[:some_flag]}"
  end
end
```

しかし、Barボタンをクリックしてみると・・・

<img width="159" alt="Screen Shot 2020-05-20 at 9.27.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/df8b0d3a-69dc-9d2b-95bf-709bccbe47a6.png">

あれっ、`some_flag`の値が空になってる！

ログを見るとこんなふうになっていて`some_flag`の値が渡されていません。

```
Started GET "/blogs/bar?button=" for 127.0.0.1 at 2020-05-20 09:13:49 +0900
```

出力されたHTMLを見てみると、`action="/blogs/bar?some_flag=1"`のように`some_flag`の値がちゃんと設定されているように見えます。

```html
<form action="/blogs/bar?some_flag=1" accept-charset="UTF-8" method="get">
  <button name="button" type="submit">Bar</button>
</form>
```

なんでだろう、おかしいなあ・・・。
原因を突き止めるためにいろいろ試行錯誤したものの、`some_flag`の値をサーバーに送信することができず、この日は諦めて寝ることにしました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">「こんな仕様変更、楽勝やわー」と思ってコードをいじったけど、なぜか思い通りに動いてくれず、「たぶんこれが原因かな？」と雑な推測を元にコードを書き換えたけど、それでも動かず、何度か試行錯誤して「うーん、今日はもうダメだな」と仕事を切り上げた。一晩頭を冷やせばきっとすぐ解決するはず!!</p>&mdash; Junichi Ito (伊藤淳一) (@jnchito) <a href="https://twitter.com/jnchito/status/1262331029961891841?ref_src=twsrc%5Etfw">May 18, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 翌日・・・解決しました！

次の日、デバッグを再開したところ、今度は原因と解決策がわかりました。
フォームをGETで送信する場合は、`action`のURLではなくhiddenタグに送信したいパラメータを含める必要があるのでした。

```erb
<%= form_tag bar_blogs_path, method: :get do %>
  <!-- hiddenタグに送信したいパラメータを含める -->
  <%= hidden_field_tag :some_flag, 1 %>
  <%= button_tag 'Bar' %>
<% end %>
```

こうすれば`some_flag`の値をサーバーに送信することができます！

<img width="156" alt="Screen Shot 2020-05-20 at 9.27.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/6d9f0caa-6df8-9423-1ab2-a2535e6d6e41.png">

ログを見ても`some_flag=1`が送信されていることがわかります。

```
Started GET "/blogs/bar?some_flag=1&button=" for 127.0.0.1 at 2020-05-20 09:22:21 +0900
```

これで解決です。めでたしめでたし。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">そういえば、昨日困っていた謎の挙動は予想通り「冷えた頭」で見直したら原因が見つかりました✨<br>他の人も僕と同じようにうっかりハマりそうな落とし穴だったので、そのうちQiitaとかに書くかも〜。</p>&mdash; Junichi Ito (伊藤淳一) (@jnchito) <a href="https://twitter.com/jnchito/status/1262606618639822850?ref_src=twsrc%5Etfw">May 19, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>