【问题标题】:Ruby on Rails: Validating and changing a phone numberRuby on Rails:验证和更改电话号码
【发布时间】:2010-07-30 00:44:35
【问题描述】:

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

【问题讨论】:

    标签: ruby-on-rails validation


    【解决方案1】:

    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 就好像它是一个普通(非动态)方法(文档中未显示但有效):

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

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

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

    这样您可以显示用户格式化的数据(即作为字符串),但仍将整数存储在数据库中。

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

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

    这将在您的表格中为您提供一个bigint(20),它可以处理高达9,223,372,036,854,775,807 的号码,这对于任何电话号码都应该足够了。

    【讨论】:

    • 很好的答案,@Niels。唯一的就是.gsub!如果未进行任何更改,则返回 nil。 .gsub 更适用于 rails 验证。见rails string length validation not working。不过,谢谢磨坊。你的回答让我开始了。
    • +1 表示 Int/BigInt 点。我从没想过这一点(无论好坏),我通常将我的电话号码存储为字符串。
    【解决方案2】:
    phone.gsub(/\D/, '')
    

    应该可以解决问题。它会删除非数字字符。

    【讨论】:

    • 我把before_validation do; phone = phone.to_s.gsub(/\D/, '').to_i; end放在我的model.rb文件中,但它仍然没有改变任何东西。
    • 正则表达式适用于 irb,Ruby 1.8.7:"(213) 456-7890".gsub(/\D/,'') =&gt; "2134567890"
    • 有许多方法可以将整数格式化为电话号码。请参阅 NumberHelper (api.rubyonrails.org/classes/ActionView/Helpers/…) 或“电话” gem (github.com/carr/phone)
    • 正如下面 Josh 所说,您需要说:ruby self.phone = phone.gsub(...) 当您更新活动记录字段时,您需要“自我”;否则 ruby​​ 假设你只是设置一个局部变量。
    【解决方案3】:
    "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

    【讨论】:

    • 唯一的问题是有些人喜欢输入电话号码,如(123)555-1234 或123-555-1234 或(123) 555-1234 等。所以这种方法并不能完全获取所有信息。
    • 在这种情况下,您可以使用更强大的正则表达式。马克在他的回答中的例子效果很好。
    【解决方案4】:

    不确定您是否已经解决了这个问题,但我遇到了与 Reti 处理 Mark 代码时相同的问题。

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

    也许是因为那时phone 还没有初始化?我不确定,这里还是新手...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-06
      • 2011-07-04
      • 2018-05-17
      • 2018-10-24
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      相关资源
      最近更新 更多