Ruby on Rails:验证和更改电话号码

时间:2010-07-30 00:44:36

标签: ruby-on-rails validation

我现在有一个简单的电话表格<%= f.text_field :phone %>:phone是一个整数类型,因此这要求用户输入表单的内容必须类似于5551234,而不是555-1234的更标准方式我如何允许用户输入在他们习惯的美国电话号码?我知道我可以使用validates_format_of来验证它,但是一旦我验证它,我如何格式化数字并将电话号码作为整数插入数据库?

4 个答案:

答案 0 :(得分:17)

ActiveRecord根据数据库列类型自动对输入进行类型转换。当Ruby将字符串转换为整数时,它会丢弃第一个非数字字符后的所有内容,123-456-7890将成为123。这是在模型中的字段可用之前完成的,因此到目前为止给出的解决方案将不起作用。您需要覆盖默认的写访问器!

ActiveRecord::Base docs提到了两种覆盖模型中默认写访问器(field_name)=的方法,因此您可以在需要进行类型转换之前处理输入删除非数字。至少有三种变体:

(1)覆盖访问者并使用write_attribute将结果存储在数据库中:

def phone=(value)
  value.gsub!(/\D/, '') if value.is_a?(String)
  write_attribute(:phone, value.to_i)
end

(2)或使用哈希表示法:

def phone=(num)
  num.gsub!(/\D/, '') if num.is_a?(String)
  self[:phone] = num.to_i
end

(3)或者(在最新版本的ActiveRecord中)只需调用super就好像它是一个普通(非动态)方法(在docs中没有显示但是有效):

def phone=(num)
  num.gsub!(/\D/, '') if num.is_a?(String)
  super(num)
end

这在许多情况下非常有用,例如带逗号的数字,并且适用于提供前一字段值的格式化版本的表单,例如编辑表单或新/创建表单中的错误之后:

<%= f.text_field :phone, number_to_phone(@model_data.phone) %>

这样您就可以显示用户格式化的数据(即String),但仍然在数据库中存储一个整数。

关于MySQL的最后一个提示:你需要使用BigInt存储一个电话号码,否则你会在数据库中看到很多(214) 748-3647个电话号码,因为2,147,483,647是最大的普通MySQL整数的值 - int(11) - 在迁移中从:integer获得。通过将BigInt设置为:limit获取MySQL中的8,如此迁移行中所示:

change_column :model_name, :phone, :integer, :limit => 8

这会在您的表格中为您提供bigint(20),可以处理最多9,223,372,036,854,775,807的数字,这对于任何电话号码都应该足够。

答案 1 :(得分:12)

phone.gsub(/\D/, '')

应该做的伎俩。它删除了非数字字符。

答案 2 :(得分:0)

"1-2-3-4".gsub('-','').to_i
# => 1234

如果你想获得更多的幻想,你也可以使用正则表达式,但你应该能够摆脱它。

您可能希望验证将其存储在数据库中的内容,因为Rails会在保存之前检查验证。但是,您可以先执行before_validation修改号码。像这样:

before_validation do
  phone = phone.to_s.gsub('-','').to_i
end

http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M001378

答案 3 :(得分:0)

不确定你是否已经解决了这个问题,但我遇到了与Reti对Mark的代码所做的相同的问题。

似乎特定的self.phone = self.phone.gsub(/\D/, '')成功了。

也许是因为那时phone尚未初始化?我不确定,还是新手......