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