JSON.parse() メソッドの型変換よりrailsのblank?メソッドを使った方が簡単だった

JavaScriptの型をどうやって変更しようか悩んだあげく、結局、railsのblank?メソッドを使って解決したという話。

かなり悩んだのでメモしておきます。



とあるアプリのバクの原因

ユーザーがセレクトボックスで選択したものをJavaScriptで処理し、値をrubyの三項演算子で処理するという簡単な処理を書いていましたが、フロントエンジニアがちょっとJavaScriptの処理を変更したため、動かなくなりました。

原因は、JavaScriptのJSON.parse() メソッドを使ったこと。

これまでは、ユーザーがセレクトボックスで未選択だったらJavaScriptで、

# JSON.stringify() メソッドは、 JavaScript オブジェクトを JSON 文字列に変換します。
string → ''

を返していましたが、JSON.parse() メソッドを使うと、これがnullで返ります。

# JSON.parse() メソッドは、 文字列をオブジェクトに変換します。
object → null

んで、これらの処理をrails側でどう処理していたのかというと。

name = params[:name] == '' ? nil : User.find(params[:name]).name

rubyの三項演算子は単純でnameがfalseだとnilを返して、値があればfindメソッドが動くというもの。

この処理がJSON.parse() メソッドのせいでエラーになった。

なぜかというとJSON.parse() メソッドの返値がObjectでnullを返すから。

公式サイトでnullの詳細をみると。

// foo が存在せず、定義も初期化もされていない場合:
> foo
"ReferenceError: foo is not defined"
// foo が存在しているが、型も値も持たない場合:
> var foo = null; foo;
"null"

javascriptのnullがクセモノで、foo が存在しているが、型も値も持たないというなんとも厄介なやつ。

先ほどの、rubyの三項演算子のはfalseの場合はnilが返るという処理にしていましたが、nullが返るせいで、存在はしているがないという意味なので、trueになってfindの処理が動いてエラーになる。

email = params[:email] == '' ? nil : User.find(params[:name]).email





railsのblank?メソッドを使う

解決したい問題は、中身が空か、または入れモノそのものが存在しないときの判定がしたい。

それを解決するのがblank?メソッド

変数.blank? nil? + empty? のようなメソッド。nilまたは空のオブジェクトをチェックできる。 nil, “”, “ “(半角スペースのみ), [](空の配列), {}(空のハッシュ) のときにfalseを返します。 Railsで拡張されたメソッドで、Rubyのみでは使えないのでご注意ください。 Railsドキュメント

blank?メソッドを使ってさっきのやつを修正するとこうなる。

email = params[:email].blank? ? nil : User.find(params[:name]).email

これで、jsでnullが返ってこようがundefinedが返ってこうようが大丈夫になった。

最初はjsでnullをundefinedにどう変更しようかなとずいぶん悩んだが、railsのblank?メソッドで解決できるという悲しい結末になりました。

See Also