0

User携帯電話番号を入れたモデルがあります。携帯電話番号は国際形式でデータベースに保存されます。ユーザーはこれに気付かず、国際形式が気に入らないことが多いため、国際プレフィックスがない場合にユーザーがローカル形式で数値を入力し、ローカル形式が表示されるように、ゲッターとセッターを変更しました。

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" 

WTF?属性が変更されました。これはゲッター機能に限定されていますか?

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

いいえ。データベースモデルでも属性を設定します。

属性に2回アクセスすると、属性が変更されます。アクセスしませんでし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!置き換えることは決してないので、あなたはただ使うほうがよいでしょう。+49sub

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 に答える