Rails の nil?, empty?, blank? の違い


Ruby on Rails で使われる少々混乱しがちな 3 つのメソッド nil?, empty?, blank? の違いを紹介します.

これらのメソッドはそれぞれ “無”, “空”, “空白” と, 同じような意味の名前に加えて, 基本的に truefalse を返す同じような挙動をするので具体的にどういう違いがあるのか少々混乱しがちです.

なので, 今回はそれらのメソッドの具体的な挙動の違いを紹介したいと思います.

Rails のバージョンは 5.2.0 になります.

nil?

nil? はオブジェクトが nil なら true を返し, nil 以外なら false を返すシンプルなメソッドです.

nil.nil?   # => true
false.nil? # => false
"".nil?    # => false
[].nil?    # => false
{}.nil?    # => false
0.nil?     # => false

empty?

empty? は String, Array, Hash などのオブジェクトの要素数が 0 だと true を返します.

具体的に次の場合 true を返します.

String の長さが 0:

"".empty?  # => true
" ".empty? # => false

Array の要素数が 0:

[].empty?   # => true
[:a].empty? # => false

Hash のキーと値のペア数が 0:

{}.empty?      # => true
{a: :A}.empty? # => false

NilClass, FalseClass, Numeric などでは empty? が定義されていないので, empty? を呼び出すと NoMethodError という例外が発生します:

nil.empty?   # => Raise `NoMethodError`
false.empty? # => Raise `NoMethodError`
0.empty?     # => Raise `NoMethodError`

blank?

blank? は Rails によって実装されている empty? の上位版のようなメソッドで, 全てのオブジェクトに使うことができます.

基本的な挙動として empty?true になるオブジェクトは blank? でも同じように true になります.

加えて empty? では false になる空白文字のみの文字列も true になり, nilfalseNoMethodError を吐き出さず true になります.

ただ Numeric は値にかかわらず false になります.

nil.blank?      # => true
false.blank?    # => true
"".blank?       # => true
" ".blank?      # => true
"\t\n\r".blank? # => true
[].blank?       # => true
{}.blank?       # => true
0.blank?        # => false

present?

present? という blank? と対になるメソッドがありますので, ついでに紹介したいと思います.

present?blank? が返す真偽値と反対の真偽値を返します.

nil.present?      # => false
false.present?    # => false
"".present?       # => false
" ".present?      # => false
"\t\n\r".present? # => false
[].present?       # => false
{}.present?       # => false
0.present?        # => true

presence

presence という present? に関連する便利なメソッドがありますので, presence もついでに紹介したいと思います.

presence の実装は present? なら self を返し, そうでないなら nil を返すというシンプルなものです:

def presence
  self if present?
end

例えば, 次のようなコードを:

prefecture = prams[:prefecture] if params[:prefecture].present?
country    = prams[:country]    if params[:country].present?
region     = prefecture || country || 'JP'

より簡潔に書き換えることができます:

region = params[:prefecture].presence || params[:country].presence || 'JP'

まとめ

Rails で nil?, empty?, blank? を使い分ける時は, 状況に応じて使い分けていただければと思います.

nil かどうかを判別する時は nil? を使い, 文字列の """ " を区別する時は empty? を使い, 区別しない時は blank? というように.

String の empty?blank? の挙動は微妙に違ったりしますので.

ただ blank?empty? と異なり呼び出せるオブジェクトが限られていないので, 多くの場合において blank? の方が使いやすいかと思います.