0

我有一个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" 

怎么回事?我的属性变了。这仅限于getter函数吗?

> u
 => #<User id: nil, mobile: "016312345", ...> 

不,它甚至在数据库模型中设置属性。

如果我两次访问该属性,则该属性会更改。我没有访问write_attribute. 为什么我的属性会改变?

4

1 回答 1

2

考虑这个简化的例子:

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!

您需要做的就是使用gsub而不是gsub!在您的 getter 中,并且由于您永远不会+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
于 2012-05-09T00:06:29.913 回答