如果 string 为空,则返回一些默认值

我经常需要检查某个值是否为空,然后像这样写“无数据存在”:

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

当我们有大约20-30个字段,我们需要处理这种方式,它变得难看。

我所做的是使用 or方法扩展 String 类

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


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

现在看起来好多了,但还是粗糙的

如何更好地解决我的问题。也许扩展 ActiveSupport class或者使用 helper 方法或 Mixin 或者其他方法会更好。红宝石理念,你的经验和最佳实践可以告诉我什么。

72171 次浏览

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.

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"

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 }

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'

It is probably better to extend ActiveRecord or individual models instead of String.

In your view, you might prefer a more explicit pattern like

@user.attr_or_default :address, "We don't know the user's address"

Ruby:

unless my_str.empty? then my_str else 'default' end

RoR:

unless my_str.blank? then my_str else 'default' end