0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FormでBooleanを渡すときの注意点!(MySQLとActiveRecordにおけるBooleanの管理方法の違い)

Posted at

はじめに

今回は、「アイテム出品時と同様に、編集する際にも最終確認画面を一枚挟みたい」というイシューを開発中に経験した思わぬ落とし穴について書いていきます!

起こったエラー

itemに紐づいた、item_optionのカラム(ここでは仮にexchange_to_point(boolean)とする)を変更する際に、最終確認画面にて

= f.fields_for :item_option do |ff|
    = ff.hidden_field :exchange_to_point, value: f.object.exchange_to_point

のようにitemに向けたformでitem.item_option.exchange_to_pointを渡し、updateアクションを呼ぼうとした際に正常に更新がされなかった。

エラー内容

Mysql2::Error: Column 'exchange_to_point' cannot be null

item_option_paramsではexchange_to_pointをpermitしていたのだが、paramsを確認すると "item_option"=>{"exchange_to_point"=>""} と本来not nullのexchange_to_pointが渡ってきていなかった。

検証&結果

f.object.exchange_to_pointの内容をdebugしてみると"false"が返ってきた。一見正常に見えたのだが、フォームタグはinputタグを生成する際にvalueとしてstring型で値を渡すため、booleanの型に正しくハマらずnilとなってしまっていたのである。
実験を行った結果、<input value="0"> で更新しようとすると成功、<input value="false"> で更新しようとすると失敗する、ということが分かった。
また、item新規作成の際は

value: f.object.exchange_to_point

<input value="0">になるのに対して、item更新時は

value: f.object.exchange_to_point ? 1 : 0

と書かないと<input value="false">になってしまうということも分かった。
それらの不思議な挙動について調査したところ、原因は「MySQLではbooleanはTINYINT(1)型で管理、すなわち[0,1]で処理されている」のに対して、「Railsではfalseとnilのみがfalse判定であり、*FALSE_VALUESは内部的にfalse に変換して扱われる」という違いにあった。

FALSE_VALUES =	[ false, 0, "0", :"0", "f", :f, "F", :F, "false", :false, "FALSE", :FALSE, "off", :off, "OFF", :OFF, ]

今回は新規登録の際にはformからの0,1が、更新時はActiveRecordのfalse,trueが渡されるため、htmlに変換した際に上記のような差が生じてしまうと考えられる。

まとめ

・フォームのvalueではbooleanであってもすべてstringに変換されるため、"false"などを渡すと正しくMySQLのbooleanが更新されないことがあるため、"0"などの値で渡すほうが安全。(MySQLではbooleanを[1, 0]で管理)
・フォームのvalueに"0"を渡すためには、ActiveRecordからデータを持ってくる際(既存レコードを更新する際など)にはRailsではbooleanを[true, false]で管理しているため明示的に[1, 0]に整形してあげる必要がある。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?