久しぶりの備忘録。
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型をパラメータとして送ることが出来ないのかもしれません。
上記以外にも、もっとスマートな解決策があれば、コメントいただければ幸いです。