この記事で書くこと
Rubyの変数に対するundefinedの挙動についての気付き
きっかけ
以下の記述は、リクエストされた動物の情報を返却するAPIを例としてあげているものです。
animal = Cat.find_by(id: params[:cat_id]) if params[:cat_id].present?
animal = Dog.find_by(id: params[:dog_id]) if params[:dog_id].present?
return render json: [] if animal.blank?
〜以下省略〜
animal.blank?
が両方の params[:cat_id] params[:dog_id]
がない場合に、
undefinedエラーが出るんじゃないかと思ったのですが、
(このように)
[1] pry(main)> hoge.blank?
NameError: undefined local variable or method `hoge' for main:Object
from (pry):1:in `<main>'
結果はエラーが出ません。
nil
になります。
当然 nil
は blank?
メソッドを持っているため、 エラーは発生しません。
なぜ?ちゃんと理解する
以下引用
宣言は、たとえ実行されなくても宣言とみなされます。
v = 1 if false # 代入は行われないが宣言は有効
p defined?(v) # => "local-variable"
p v # => nil
式として評価されなくても宣言自体はされてるということか。。。。
一人でもわかりにくい。。と感じたということは、書き方を変えた方がいい。
animal = Cat.find_by(id: params[:cat_id]) if params[:cat_id].present?
animal = Dog.find_by(id: params[:dog_id]) if params[:dog_id].present?
return render json: [] if animal.blank?
ではなく、
こうした方が読みやすいと思いました。
なんとなくビューで変数を扱ってる時は、気にならなかったことが、
今回の業務のメンバーへのコードレビューをしている時に気になった。
気を付けて行こう。また一つ学んだ!
animal = nil
animal = Cat.find_by(id: params[:cat_id]) if params[:cat_id].present?
animal = Dog.find_by(id: params[:dog_id]) if params[:dog_id].present?
return render json: [] if animal.blank?
[追記]
コメントにて、
animal = nil
で明示的に宣言することは不要なコードで、迷いを産む可能性があるとのコメントをいただきました。
自分の理解が不足していて入れてしまいそうになっていたコードですが、
以下のコードで何ら問題のないものです。
animal = Cat.find_by(id: params[:cat_id]) if params[:cat_id].present?
animal = Dog.find_by(id: params[:dog_id]) if params[:dog_id].present?
return render json: [] if animal.blank?