はじめに:イントロダクション
以下のような単純なRailsのフォームがあったとします。
<%= form_tag foo_blogs_path(some_flag: 1) do %>
<%= button_tag 'Foo' %>
<% end %>
コントローラのコードは次のようにsome_flag
の値をnoticeに出力するようになっています。
class BlogsController < ApplicationController
def foo
redirect_to :blogs, notice: "Foo / some_flag: #{params[:some_flag]}"
end
end
以下はFooボタンをクリックしたときの実行結果です。
フォームのURLに設定したsome_flag: 1
の値が表示されています。
本題:困ったこと
上の例と同じようなことを以下のようなフォームでもやろうとしました。
<%= form_tag bar_blogs_path(some_flag: 1), method: :get do %>
<%= button_tag 'Bar' %>
<% end %>
先ほどのコード例と違うのはフォームのHTTPメソッドがGETになっている点(method: :get
)です。
コントローラ側のコードはほぼ同じです。
class BlogsController < ApplicationController
def bar
redirect_to :blogs, notice: "Bar / some_flag: #{params[:some_flag]}"
end
end
しかし、Barボタンをクリックしてみると・・・
あれっ、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
の値がちゃんと設定されているように見えます。
<form action="/blogs/bar?some_flag=1" accept-charset="UTF-8" method="get">
<button name="button" type="submit">Bar</button>
</form>
なんでだろう、おかしいなあ・・・。
原因を突き止めるためにいろいろ試行錯誤したものの、some_flag
の値をサーバーに送信することができず、この日は諦めて寝ることにしました。
「こんな仕様変更、楽勝やわー」と思ってコードをいじったけど、なぜか思い通りに動いてくれず、「たぶんこれが原因かな?」と雑な推測を元にコードを書き換えたけど、それでも動かず、何度か試行錯誤して「うーん、今日はもうダメだな」と仕事を切り上げた。一晩頭を冷やせばきっとすぐ解決するはず!!
— Junichi Ito (伊藤淳一) (@jnchito) May 18, 2020
翌日・・・解決しました!
次の日、デバッグを再開したところ、今度は原因と解決策がわかりました。
フォームをGETで送信する場合は、action
のURLではなくhiddenタグに送信したいパラメータを含める必要があるのでした。
<%= form_tag bar_blogs_path, method: :get do %>
<!-- hiddenタグに送信したいパラメータを含める -->
<%= hidden_field_tag :some_flag, 1 %>
<%= button_tag 'Bar' %>
<% end %>
こうすればsome_flag
の値をサーバーに送信することができます!
ログを見てもsome_flag=1
が送信されていることがわかります。
Started GET "/blogs/bar?some_flag=1&button=" for 127.0.0.1 at 2020-05-20 09:22:21 +0900
これで解決です。めでたしめでたし。
そういえば、昨日困っていた謎の挙動は予想通り「冷えた頭」で見直したら原因が見つかりました✨
— Junichi Ito (伊藤淳一) (@jnchito) May 19, 2020
他の人も僕と同じようにうっかりハマりそうな落とし穴だったので、そのうちQiitaとかに書くかも〜。