我可以使用小写字母吗!而不是在 before_save 挂钩中小写来更改值?
Can I use downcase! instead of downcase in a before_save hook to change a value?
我是 Ruby 的新手。我在 Rails 教程 上做 Michael Hartl 的 Ruby,以下代码用于用户的模型:
before_save { self.email = email.downcase }
在这种情况下,是否可以改写:
before_save { self.email.downcase! }
或者这种方法是否出于某种原因存在缺陷?如果是,您能否快速解释一下原因?
这里用downcase!
修改属性是完全可以接受的,只要你能保证设置了email
。在 email
为 nil
的情况下,如果您尝试对其调用 downcase!
,则会遇到 NoMethodError
。这也适用于您的第一个示例。
顺便说一句,确实没有必要指定 self
来访问模型的属性。以下是完全足够的。 (添加检查是否存在电子邮件。)
before_save { email.downcase! if email }
TL;博士
In this context, would it be acceptable to instead write
before_save { self.email.downcase! }
or is this approached flawed for some reason?
不要这样做,除非 bang 方法位于方法链的末尾,或者除非您确定知道您不关心 return 值。否则 Bad Things™ 可能会发生。
相反,您应该使用处理极端情况的东西,例如以下之一:
before_save { self.email.downcase! unless self.email.blank? }
before_save { self.email = self.email.to_s.downcase }
说明
一些像 String#downcase! 这样的 bang 方法的问题在于它们不提供您认为它们提供的 return 值。虽然 self.email.downcase!
会将自身的 email 属性小写,但 return 值可能为 nil。例如:
"A".downcase!
#=> "a"
"".downcase!
#=> nil
"z".downcase!
#=> nil
更糟糕的是,如果 email 为 nil,则无论您使用 downcase
还是 downcase!
都会引发异常。例如:
nil.downcase
# NoMethodError: undefined method `downcase' for nil:NilClass
为了简单地确保 email 属性是小写的,那么在 strong params 或其他因素确保email 不是零,并且您没有使用方法或挂钩的 return 值。不过,更广泛地说,火车失事就像:
before_save { self.email.downcase!.gsub(?@, ' AT ') }
可能会在运行时以令人惊讶且难以调试的方式爆炸。
总而言之,您当前的示例 看起来 功能相同,但处理 return 值的方式完全不同。因此,您的里程可能会有所不同。
原来的方法调用属性setter方法email=
,因此要走的路:
self.email= email.downcase
ActiveRecord 可以做更多的事情。例如,它可能会跟踪更改的属性以优化数据库更新。
用downcase!
改的时候,是先调用getter,ActiveRecord returns这个字符串,然后就地改字符串,ActiveRecord不是直接意识到这一点。也许它在这个例子中有效,但不要养成这种习惯更安全。
我是 Ruby 的新手。我在 Rails 教程 上做 Michael Hartl 的 Ruby,以下代码用于用户的模型:
before_save { self.email = email.downcase }
在这种情况下,是否可以改写:
before_save { self.email.downcase! }
或者这种方法是否出于某种原因存在缺陷?如果是,您能否快速解释一下原因?
这里用downcase!
修改属性是完全可以接受的,只要你能保证设置了email
。在 email
为 nil
的情况下,如果您尝试对其调用 downcase!
,则会遇到 NoMethodError
。这也适用于您的第一个示例。
顺便说一句,确实没有必要指定 self
来访问模型的属性。以下是完全足够的。 (添加检查是否存在电子邮件。)
before_save { email.downcase! if email }
TL;博士
In this context, would it be acceptable to instead write
before_save { self.email.downcase! }
or is this approached flawed for some reason?
不要这样做,除非 bang 方法位于方法链的末尾,或者除非您确定知道您不关心 return 值。否则 Bad Things™ 可能会发生。
相反,您应该使用处理极端情况的东西,例如以下之一:
before_save { self.email.downcase! unless self.email.blank? }
before_save { self.email = self.email.to_s.downcase }
说明
一些像 String#downcase! 这样的 bang 方法的问题在于它们不提供您认为它们提供的 return 值。虽然 self.email.downcase!
会将自身的 email 属性小写,但 return 值可能为 nil。例如:
"A".downcase!
#=> "a"
"".downcase!
#=> nil
"z".downcase!
#=> nil
更糟糕的是,如果 email 为 nil,则无论您使用 downcase
还是 downcase!
都会引发异常。例如:
nil.downcase
# NoMethodError: undefined method `downcase' for nil:NilClass
为了简单地确保 email 属性是小写的,那么在 strong params 或其他因素确保email 不是零,并且您没有使用方法或挂钩的 return 值。不过,更广泛地说,火车失事就像:
before_save { self.email.downcase!.gsub(?@, ' AT ') }
可能会在运行时以令人惊讶且难以调试的方式爆炸。
总而言之,您当前的示例 看起来 功能相同,但处理 return 值的方式完全不同。因此,您的里程可能会有所不同。
原来的方法调用属性setter方法email=
,因此要走的路:
self.email= email.downcase
ActiveRecord 可以做更多的事情。例如,它可能会跟踪更改的属性以优化数据库更新。
用downcase!
改的时候,是先调用getter,ActiveRecord returns这个字符串,然后就地改字符串,ActiveRecord不是直接意识到这一点。也许它在这个例子中有效,但不要养成这种习惯更安全。