0
0

More than 3 years have passed since last update.

Rubyのローカル変数定義について難しいという今日の気付き

Last updated at Posted at 2020-12-29

この記事で書くこと

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 になります。

当然 nilblank? メソッドを持っているため、 エラーは発生しません。

なぜ?ちゃんと理解する

Ruby 3.0.0 リファレンスマニュアル 変数と定数

以下引用

宣言は、たとえ実行されなくても宣言とみなされます。

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

で明示的に宣言することは不要なコードで、迷いを産む可能性があるとのコメントをいただきました。
自分の理解が不足していて入れてしまいそうになっていたコードですが、
以下のコードで何ら問題のないものです。 :bow:

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

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