LoginSignup
14
10

More than 5 years have passed since last update.

【備忘録】初心者がenum使ったf.check_boxで見事につまづいた話

Last updated at Posted at 2017-03-15

rails f.check_boxの妖艶な動きに騙されるな!

checkboxを生成してくれるrailsのヘルパーがあるのだが、けっこうハマったのでメモ。

見積もりを1時間ほどとしていた軽めのバグタスクがあったのだが、手を付け始めてから結構長い間プルリクをオープン状態のまま放置していた。というのも、バグっている箇所とほぼ同じコードを書いているはずの箇所がちゃんと動いてしまっており、「これもしかしたらハマるかも」と思ったからだ(実際結構ハマった)。何でハマったか、ちゃんと残しておこうb
結論から言うと、「f.check_boxのchecked_value、unchecked_valueにはシンボルではなくstringを入れておこう」ということ。
バグってたのは以下のコード。

app/models/hoge.rb
# == Schema Information
#
# Table name: hoges
#
#  id         :integer          not null, primary key
#  foo        :integer          default(0), not null
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class Hoge < ActiveRecord::Base
  enum foo: %i(foo_ng foo_ok)
end
app/views/hoge.html.erb
〜〜〜
<%= f.label :foo do %>
  <%= f.check_box :foo, {}, :foo_ok, :foo_ng %>
  <%= label_tag 'hoge_foo', '' %>
  <%= f.label :foo, 'fooはokです' %>
<% end %>
〜〜〜

f.check_boxのドキュメントを見ると、引数は以下の順番。
1. プロパティ名
2. オプション
3. checked_value (default: "1")
4. unchecked_value (default: "0")

上記のコードでは、チェックを入れればfoo_ok(つまり0)がsubmitされる。だから、チェックしてsubmit後そのページに戻ってきたときは、デフォでチェックされてるはず...なのだが、チェックされてなかった、というのが直すべきバグ内容。なんでだろ??
同じようなコードを書いているところとの違いは、enumを使ってなんかゴチャゴチャやってるかどうかくらい。でもそれしか違いがないんだから、多分それがバグの要因なんだろう。ここまでは分かった。でもその先どう解決すべきかがよく分からなくて結構時間をとられた。以下、解決までの流れ。

  • 「rails check box enum」でググってみた
    • が、それらしきものが見当たらず...
  • とりあえずあまり得策ではないものの、オプションのcheckedをvalue見て変える形で実装
    • まぁそりゃあ...動くっちゃあ動く
    • でも、やっぱりコレジャナイ感がすごい
    • そもそもf.check_boxならformの要素渡ってるはず
    • checked渡さずとも、正しい挙動ならデフォでチェックが入るはず
    • ということは...?
  • formを作るところで間違っている(ヘルパーに渡すものが違う)のかも
    • なんか怪しいのは、やはり引数の3番目と4番目のchecked_value & unchecked_value
    • 試しにフォーム要素@hogeから@hoge.foos.key[0]みたいな感じで取ってくると、動いた
    • 動かなかったやつと動いたやつで、生成されたhtmlを確認してみる
    • checked="checked" 以外同じやんけ!!!!!!
    • ということは...?
    • 別に@hoge.foos.key[0]でなくてもいいよね、これって別にフォーム要素関係ないし(どちらかというとクラスの話)
    • 試しに 'foo_ok' とか文字列ブチ込んだろ
    • 動いた
  • 動いた
    • ということは...?
  • これ文字列じゃないとだめなやつじゃね...?

ということでした。つまるところ、

[1] pry(main)> 'aaa' == :aaa
=> false

やで!ということです。

今回の学び

  • 「どうなってるのかよく分からんけど、動いた」は危ない
    • この場合はうまくいくかもしれないけど、次にもし、同じようで同じじゃない、少し同じバグが出てきたときに対処できない可能性がある
    • なんで動かなかったのか?なんで動いたのか?を理解することを心がける
  • ソースコードともっと仲良くなる
    • なんか謎な動き方してると思ったら、ソースコードをあたってみること。大抵書いてある
14
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10