nil?, empty?, blank? trong Ruby on Rails - sự khác biệt thực sự là gì

nil?

  • Cung cấp bởi Ruby
  • Có thể sử dụng trên bất kỳ đối tượng nào
  • Sẽ chỉ trả về true khi thực sự là nil. Ví dụ:
nil.nil?
# => true

false.nil?
# => false

0.nil?
# => false

"".nil?
# => false

empty?

  • Đây cũng là phương thức được cung cấp bởi Ruby
  • Khác với nil?, empty? chỉ sử dụng trên các đối tượng dạng tập hợp(collection) như Hash, Array, Set
  • Phương thức sẽ trả về true khi tập hợp không có phần tử nào Ví dụ:
[].empty?
# => true

{}.empty?
# => true

Set.new.empty?
# => true
  • Tuy nhiên, phương thức này lại không bao gồm trong Enumerable, nguyên nhân là bởi không phải kiểu Enumerable nào khi lặp cũng trả về giá trị. Để biết thêm thông tin có thể tham khảo tại đây Ví dụ:
fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end

fib.empty?
# NoMethodError: undefined method `empty?' for #<Enumerator:
  • Bạn cũng có thể sử dụng empty với String (bởi vì String là mảng các ký tự). Ví dụ:
"".empty?
# => true

" ".empty?
# => false
  • Vấn đề khi sử dụng empty? là bạn phải biết chắc chắn rằng kiểu của đối tượng bạn đang sử dụng là Array hay nil. Nếu không biết trước điều này thì sử dụng nó sẽ không an toàn. Khi đó, bạn sẽ cần check điều kiện nil? trước. Ví dụ:
object = rand > 0.5 ? nil : array
object.empty? # can raise an exception

if !object.nil? && !object.empty? # doh...
  # do something
end

Đó chính là lý do mà Rails định nghĩa phương thức blank? trong ActiveSupport.

blank?

  • Cung cấp bởi Rails
  • nilfalse rõ ràng là blank còn true thì không.
class NilClass
  def blank?
    true
  end
end

class FalseClass
  def blank?
    true
  end
end

class TrueClass
  #   true.blank? # => false
  def blank?
    false
  end
end
  • Đối với ArrayHash thì là blank? khi chúng empty. Điều này được thực hiện bằng cách sử dụng alias_method như bên dưới:
class Array
  #   [].blank?      # => true
  #   [1,2,3].blank? # => false
  alias_method :blank?, :empty?
end

class Hash
  #   {}.blank?                # => true
  #   { key: 'value' }.blank?  # => false
  alias_method :blank?, :empty?
end
  • Khác với String#empty? chỉ kiểm tra trên độ dài của chuỗi thì String#blank? còn kiểm tra thêm cả khoảng trắng. Ví dụ:
class String
  BLANK_RE = /\A[[:space:]]*\z/

  # A string is blank if it's empty or contains whitespaces only:
  #
  #   ''.blank?       # => true
  #   '   '.blank?    # => true
  #   "\t\n\r".blank? # => true
  #   ' blah '.blank? # => false
  #
  # Unicode whitespace is supported:
  #
  #   "\u00a0".blank? # => true
  #
  def blank?
    # The regexp that matches blank strings is expensive. For the case of empty
    # strings we can speed up this method (~3.5x) with an empty? call. The
    # penalty for the rest of strings is marginal.
    empty? || BLANK_RE.match?(self)
  end
end

Điều này thuận tiện cho các ứng dụng web vì bạn thường muốn từ chối hoặc xử lý các chuỗi khác nhau chỉ chứa các khoảng trắng. - Logic cho các class khác là nếu nó có cài đặt empty? thì có thể sử dụng được blank?. Điều này thật thú vị. Hãy nhìn cách cài đặt blank? cho Object ở dưới:

class Object
  # An object is blank if it's false, empty, or a whitespace string.
  # For example, +false+, '', '   ', +nil+, [], and {} are all blank.
  #
  # This simplifies
  #
  #   !address || address.empty?
  #
  # to
  #
  #   address.blank?
  #
  # @return [true, false]
  def blank?
    respond_to?(:empty?) ? !!empty? : !self
  end

Trong đó, !!empty? chỉ sự phủ định nhân đôi, điều này rất hữu ích trong trường hợp giá trị là nil, một chuỗi số hay các giá trị trả về là true, false khác. Bằng cách này giá trị trả về luôn được chuyển sang kiểu boolean:

!!true
# => true

!!false
# => false

!!nil
 => false

!!0
# => true

!!"abc"
# => true
  • Number và Time sẽ không có blank?. Chúng sẽ luôn trả về false.
class Numeric #:nodoc:
  #   1.blank? # => false
  #   0.blank? # => false
  def blank?
    false
  end
end

class Time #:nodoc:
  #   Time.now.blank? # => false
  def blank?
    false
  end
end

present?

  • Được cung cấp bởi Rails
  • present? là phủ định của blank? và có thể sử dụng ở bất cứ đâu
class Object
  # An object is present if it's not blank.
  def present?
    !blank?
  end
end

presence

  • Cung cấp bởi Rails. Đôi khi bạn muốn viết một logic như:
params[:state] || params[:country] || 'US'

Nhưng bởi vì các tham số được nhập từ form nên đôi khi chúng có thể rỗng("") và khi đó chúng sẽ trả về ' ' thay vì 'US' như mong muốn. Lúc này thì presence rất hữu ích. Thay vì phải viết

state   = params[:state]   if params[:state].present?
country = params[:country] if params[:country].present?
region  = state || country || 'US'

thì bạn có thể viết là

params[:state].presence || params[:country].presence || 'US'
  • Phương thức này được cài đặt rất đơn giản:
class Object
  def presence
    self if present?
  end
end

Vậy bạn nên sử dụng cái nào?

Nếu bạn làm việc với Rails, tôi khuyên bạn nên sử dụng prensent? hoặc blank? hoặc cả hai. Chúng có thể làm việc trên tất cả các đối tượng, làm việc trực quan tốt hơn và bạn không phải kiểm tra nil ở bất kỳ đâu.

Tham khảo

Bài viết gốc: https://blog.arkency.com/2017/07/nil-empty-blank-ruby-rails-difference/


All Rights Reserved