はじめに
例えば、以下の様なフォームがあった場合、
<%= form_for @user do |f| %>
<%= f.check_box :enabled %>
<% end %>
チェックの有無に応じて、サーバサイドの処理を分岐させるために以下のようなコードが書きたくなる場合がある。
if params[:user][enabled] == '1' # or 1.to_s
do_something
end
でも、上記のコードだと、特定の文字列リテラルを直接比較に使っているため、次のような意見をもらったりする。
- Viewが修正されて、
'1'
ではなく'true'
という文字列が渡されてきた時にどうする? -
'1'
がマジックストリング的で意図がわかりにくい
※ マジックストリングかどうかは議論の余地あるけど、Rubyだと0
も1
も真なので気持ちはわかる
じゃあ、どう書き換えればいいかという話。
Rails 4.2の場合
ActiveRecord::Type::Boolean#type_cast_from_user
メソッドが使える。
引数と戻り値は以下のようなパターンになる。
ActiveRecord::Type::Boolean.new.type_cast_from_user(0) # false
ActiveRecord::Type::Boolean.new.type_cast_from_user(1) # true
ActiveRecord::Type::Boolean.new.type_cast_from_user('0') # false
ActiveRecord::Type::Boolean.new.type_cast_from_user('1') # true
ActiveRecord::Type::Boolean.new.type_cast_from_user(false) # false
ActiveRecord::Type::Boolean.new.type_cast_from_user(true) # true
ActiveRecord::Type::Boolean.new.type_cast_from_user('false') # false
ActiveRecord::Type::Boolean.new.type_cast_from_user('true') # true
ActiveRecord::Type::Boolean.new.type_cast_from_user(nil) # nil
冒頭のコードは以下のようになる。
if ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:user][:enabled])
do_something
end
Rails 5の場合
Rails 4.2系で使えた上記メソッドが削除されている。
代わりにActiveRecord::Type::Boolean#cast
メソッドが使える。
引数と戻り値は以下のようなパターンになる。
(ActiveRecord::Type::Boolean#type_cast_from_user
と同じ)
ActiveRecord::Type::Boolean.new.cast(0) # false
ActiveRecord::Type::Boolean.new.cast(1) # true
ActiveRecord::Type::Boolean.new.cast('0') # false
ActiveRecord::Type::Boolean.new.cast('1') # true
ActiveRecord::Type::Boolean.new.cast(false) # false
ActiveRecord::Type::Boolean.new.cast(true) # true
ActiveRecord::Type::Boolean.new.cast('false') # false
ActiveRecord::Type::Boolean.new.cast('true') # true
ActiveRecord::Type::Boolean.new.cast(nil) # nil
冒頭のコードは以下のようになる。
if ActiveRecord::Type::Boolean.new.cast(params[:user][:enabled])
do_something
end
所感
マジックストリング(?)は排除できたけど、コードをパット見ても、何をやっているのか少しわかりづらくなった感じがする。
ifの条件式に直接指定するのは気が進まないので、条件判定用のメソッドを切り出す感じにするかなぁ。
def enabled?(user)
ActiveRecord::Type::Boolean.new.cast(user[:enabled])
end
if enabled?(params[:user])
do_something
end
ここまでやる必要があるかについてはわからない。