If string is empty then return some default value

Often I need to check if some value is blank and write that "No data present" like that:

@user.address.blank? ? "We don't know user's address" : @user.address

And when we have got about 20-30 fields that we need to process this way it becomes ugly.

What I've made is extended String class with or method

class String
  def or(what)
    self.strip.blank? ? what : self
  end
end

@user.address.or("We don't know user's address")

Now it is looking better. But it is still raw and rough

How it would be better to solve my problem. Maybe it would be better to extend ActiveSupport class or use helper method or mixins or anything else. What ruby idealogy, your experience and best practices can tell to me.


Solution 1:

ActiveSupport adds a presence method to all objects that returns its receiver if present? (the opposite of blank?), and nil otherwise.

Example:

host = config[:host].presence || 'localhost'

Solution 2:

Phrogz sort of gave me the idea in PofMagicfingers comment, but what about overriding | instead?

class String
  def |(what)
    self.strip.blank? ? what : self
  end
end

@user.address | "We don't know user's address"

Solution 3:

Since you're doing this in Ruby on Rails, it looks like you're working with a model. If you wanted a reasonable default value everywhere in your app, you could (for example) override the address method for your User model.

I don't know ActiveRecord well enough to provide good code for this; in Sequel it would be something like:

class User < Sequel::Model
  def address        
    if (val=self[:address]).empty?
      "We don't know user's address"
    else
      val
    end
  end
end

...but for the example above this seems like you'd be mixing view logic into your model, which is not a good idea.

Solution 4:

Your or method might have some unwanted side-effects, since the alternative (default) value is always evaluated, even if the string is not empty.

For example

@user.address.or User.make_a_long_and_painful_SQL_query_here

would make extra work even if address is not empty. Maybe you could update that a bit (sorry about confusing one-liner, trying to keep it short):

class String
  def or what = ""
    self.strip.empty? ? block_given? ? yield : what : self
  end
end

@user.address.or "We don't know user's address"
@user.address.or { User.make_a_long_and_painful_SQL_query_here }