我是Ruby新手。我正在做Michael Hartl的 Rails Tutorial ,并且在用户的模型中使用了以下代码:
before_save { self.email = email.downcase }
在这种情况下,可以接受写:
before_save { self.email.downcase! }
或者由于某种原因这是否存在缺陷?如果是的话,你能给我一个快速解释原因吗?
答案 0 :(得分:5)
在这种情况下,可以接受写
before_save { self.email.downcase! }
或者由于某种原因,这是否存在缺陷?
除非爆炸方法在方法链的末尾,或者除非您确定肯定您不关心返回值,否则不要这样做。 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!
会将自己的电子邮件属性放在一边,但返回值可能为零。例如:
"A".downcase!
#=> "a"
"".downcase!
#=> nil
"z".downcase!
#=> nil
更糟糕的是,如果电子邮件为零,则无论您使用downcase
还是downcase!
,都会引发异常。例如:
nil.downcase
# NoMethodError: undefined method `downcase' for nil:NilClass
为了简单地确保电子邮件属性是小写的,那么您可能会在strong params或其他因素确保电子邮件<的狭窄环境中侥幸成功/ em>不是nil,并且您没有使用方法或钩子的返回值。但更广泛地说,火车失事如:
before_save { self.email.downcase!.gsub(?@, ' AT ') }
可能会在运行时以令人惊讶且难以调试的方式爆炸。
总结一下,您当前的示例似乎在功能上等效,但处理返回值的方式完全不同。因此,您的里程可能会有所不同。
答案 1 :(得分:0)
只要您可以保证设置downcase!
,就可以使用email
来修改此处的属性。在email
为nil
的情况下,如果您尝试在其上调用NoMethodError
,则会遇到downcase!
。这也适用于您的第一个示例。
顺便说一句,实际上没有必要指定self
来访问模型上的属性。以下是完全足够的。 (添加检查是否存在电子邮件。)
before_save { email.downcase! if email }
答案 2 :(得分:0)
原始方法调用属性setter方法email=
,因此是可行的方法:
self.email= email.downcase
然后,ActiveRecord可以执行其他操作。例如,它可能会跟踪更改的属性以优化数据库更新。
当你用downcase!
更改它时,你首先调用getter,ActiveRecord返回字符串,然后你就改变了字符串,而ActiveRecord并没有直接意识到这一点。也许它在这个例子中起作用,但不习惯这种习惯更安全。