久しぶりの備忘録。
RailsでPOSTで送った false がif文にて true になってしまう問題に遭遇し、解決までにちょっと悩んだので記事にしました。(検索した限りではQiitaでの記事が無かったので)
バグ
~省略~
<%= link_to stock_path(num: num, is_sum: false), method: "post", class: "btn btn-success btn-block" do %>
	<i class="glyphicon glyphicon-ok"></i> stockから減らす
<% end %>
~省略~
def stock
	if !params[:is_sum]
		stock -= params[:num]
	else
		stock += params[:num]
	end
end
適当に書いたsampleなので間違ってたらごめんなさい
上記のコードは、AAA.html.erbのViewにある「stockから減らす」ボタンを押すと、stockからnum個減らすというものです。
BBB#stock は、is_sumがtrueならstockにnumを加算、is_sumがfalseならstockからnumを減算するアクションです。
AAA.html.erb上のボタンでは、is_sum == false であるので、当然ボタンを押すと減算されるはず......だったのですが、実際に動かしてみるとelse文の方に入っていき、numが加算されてしまうのでした。
logを使って見てみるも、きちんとis_sumにはfalseが入っていた...
原因
答えから言えば原因は
- Rubyでは、falseになるのはFalseClassかnilの場合のみ(0や"false"はtrue)
- paramsとして論理値を渡す時、勝手にstringになっている
そう、is_sumに入っていたのは、falseではなく"false"であった...
解決
stringになっているだけなので
if params[:is_sum] == "false"
	stock -= params[:num]
else
	stock += params[:num]
end
のように、文字列一致を条件にすれば、キチンと動作しました。
また、helperとかにstringからBooleanに戻す関数を用意するのも良いと思います。
※RubyにはString→Booleanの型変換ができる関数がないので、自作する必要があります
参考資料 : http://portaltan.hatenablog.com/entry/2015/07/29/130359
最後に
勝手にstringに変換されるのは盲点でした。
もしかするとPOSTではboolean型をパラメータとして送ることが出来ないのかもしれません。
上記以外にも、もっとスマートな解決策があれば、コメントいただければ幸いです。