我可以使用downcase!而不是在before_save挂钩中使用downcase来更改值?

Par*_*er 0 ruby string hook ruby-on-rails before-save

我是Ruby的新手.我正在做Michael Hartl的Ruby on Rails教程,并在用户的模型中使用以下代码:

before_save { self.email = email.downcase }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,可以接受写:

before_save { self.email.downcase! }
Run Code Online (Sandbox Code Playgroud)

或者由于某种原因这是否有缺陷?如果是的话,你能给我一个快速解释原因吗?

Tod*_*obs 5

TL; DR

在这种情况下,可以接受写作

before_save { self.email.downcase! }
Run Code Online (Sandbox Code Playgroud)

或者由于某种原因这是否有缺陷?

除非爆炸方法位于方法链的末尾,或者除非您确定不关心返回值,否则不要这样做.Bad Things™会发生其他情况.

相反,您应该使用处理极端情况的内容,例如以下之一:

  • before_save { self.email.downcase! unless self.email.blank? }
  • before_save { self.email = self.email.to_s.downcase }

说明

一些爆炸方法的问题,比如String#downcase!是他们没有提供你认为他们做的回报值.虽然self.email.downcase!将在self上保留电子邮件属性,但返回值可能为零.例如:

"A".downcase!
#=> "a"

"".downcase!
#=> nil

"z".downcase!
#=> nil
Run Code Online (Sandbox Code Playgroud)

更糟糕的是,如果电子邮件是零,无论您使用downcase或是,都会引发异常downcase!.例如:

nil.downcase
# NoMethodError: undefined method `downcase' for nil:NilClass
Run Code Online (Sandbox Code Playgroud)

为了简单地确保电子邮件属性是小写的,那么在狭窄的环境中你可能会逃避这一点,在这种情况下强大的参数或其他因素确保电子邮件不是零,并且你没有使用你的方法的返回值或钩.更广泛地说,火车失事如下:

before_save { self.email.downcase!.gsub(?@, ' AT ') }
Run Code Online (Sandbox Code Playgroud)

可能会在运行时以令人惊讶且难以调试的方式爆炸.

回顾一下,您当前的示例功能上看起来是等效的,但处理返回值的方式完全不同.因此,您的里程可能会有所不同