我有一个User
型号,其中包含一个手机号码。手机号码将以国际格式保存在数据库中。由于用户通常不知道这一点并且不喜欢国际格式,因此我更改了getter和setter,以便用户能够以本地格式输入数字,并且如果没有国际前缀,则会显示本地格式。
class User < ActiveRecord::Base
def mobile=(number)
# Strip whitespace, dashes and slashes first
[" ", "-", "/", "\"].each do |particle|
number.gsub!(particle, "")
end
# Check if there is leading 00, this indicates a
# country code.
number.gsub!(/^00/,"+")
# Check if there is only one leading zero. If there is,
# treat as German number
number.gsub!(/^0/,"+49")
# Now write to attribute. Validate later.
puts "Writing: #{number}"
write_attribute(:mobile, number)
end
def mobile
number = read_attribute(:mobile)
puts "Reading: #{number}"
# If this is a German number, display as local number.
number.gsub!(/+49/,"0")
number
end
end
现在,这似乎没有像预期的那样工作。这是我rails console
会议:
> u = User.new(:mobile => "0163 12345")
Writing: +4916312345
=> #<User id: nil, mobile: "+4916312345", ...>
这按预期工作。因此,让我们检查一下吸气剂:
> u.mobile
Reading: +4916312345
=> "016312345"
看起来不错。但最好再检查一次:
> u.mobile
Reading: 016312345
=> "016312345"
跆拳道?我的属性变了。这是否仅限于吸气器功能?
> u
=> #<User id: nil, mobile: "016312345", ...>
不。它甚至在数据库模型中设置属性。
如果我访问该属性两次,该属性会发生变化。我无法访问write_attribute
.为什么我的属性会改变?
考虑这个简化的例子:
class User
def initialize
@attributes = { :mobile => "+4916312345" }
end
def read_attribute name
@attributes[name]
end
end
请注意,read_attribute
返回属性的值,而不是值的副本。
现在:
user = User.new
mobile = user.read_attribute :mobile
=> "+4916312345"
mobile.gsub!(/+49/,"0")
=> "016312345"
mobile = user.read_attribute :mobile
=> "016312345" # because we modified it in place with gsub!
您需要做的就是在 getter 中使用 gsub
而不是 gsub!
,并且由于您永远不会在同一字符串中多次替换+49
,因此您不妨只使用 sub
.
def mobile
number = read_attribute(:mobile)
puts "Reading: #{number}"
# If this is a German number, display as local number.
number.sub(/+49/,"0")
end