首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >重构复杂电话验证

重构复杂电话验证
EN

Code Review用户
提问于 2014-08-15 18:39:49
回答 2查看 117关注 0票数 2

我有一个复杂的电话验证,它执行以下操作:

  1. 首先,检查是否提供家庭电话、移动电话或工作电话(在形式上将有3个文本字段,并且至少需要一种类型的电话号码)。
  2. 从电话号码中删除除'x‘和'+’以外不是数字的任何字符,因为它们代表扩展名并且是有效的。
  3. 确保所提供的手机确实通过了电话号码regex测试。

下面是我实现上述三个步骤的方式:

代码语言:javascript
运行
复制
  VALID_PHONE_FORMAT = /\A(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?\z/

  validate :phone_provided
  before_validation :clean_phone_numbers
  validates_format_of :phone_home, with: VALID_PHONE_FORMAT, if: :home_is_filled?
  validates_format_of :phone_mobile, with: VALID_PHONE_FORMAT, if: :mobile_is_filled?
  validates_format_of :phone_work, with: VALID_PHONE_FORMAT, if: :work_is_filled?
  validates_format_of :phone_fax, with: VALID_PHONE_FORMAT, if: :fax_is_filled?

 private

  def clean_phone_numbers
    if phone_home.present?
      self[:phone_home] = strip_bad_characters :phone_home
    end
    if phone_mobile.present?
      self[:phone_mobile] = strip_bad_characters :phone_mobile
    end
    if phone_work.present?
      self[:phone_work] = strip_bad_characters :phone_work
    end
    if phone_fax.present?
      self[:phone_fax] = strip_bad_characters :phone_fax
    end
  end

  def strip_bad_characters(attr)
    send("#{attr}_before_type_cast").gsub(/[^\d+!x]/,'')
  end

  def phone_provided
    if phone_home.blank? && phone_mobile.blank? && phone_work.blank?
      errors.add(:base, "Must provide a phone number")
    end
  end

  def home_is_filled?
    !phone_home.blank?
  end

  def mobile_is_filled?
    !phone_mobile.blank?
  end

  def work_is_filled?
    !phone_work.blank?
  end

  def fax_is_filled?
    !phone_fax.blank?
  end

我特别不喜欢在if条件下为validates_format_of调用4种不同的方法。我只想使用一种方法,并且能够分辨调用blank?的属性。我怎么才能重构这个呢?

EN

回答 2

Code Review用户

回答已采纳

发布于 2014-08-15 19:09:19

让我们总结一下业务规则:

  1. 除数字、!x以外的字符将被删除。
  2. 如果提供了四种类型的电话号码中的任何一种,则必须是有效的。
  3. 必须至少提供一个{ home,mobile,work }。

需求3是由validate :phone_provided处理的,它简单而精细。

这种不满来自于实现需求1和2。

通过使strip_bad_characters()能够容忍nil,可以简化需求1的实现。您也可以调用#read_attribute_before_type_cast()以避免插值。

代码语言:javascript
运行
复制
def strip_bad_characters(attr)
  input = read_attribute_before_type_cast(attr)
  input.gsub(/[^\d+!x]/, '') if input
end

此外,clean_phone_numbers()还可以使用循环:

代码语言:javascript
运行
复制
def clean_phone_numbers
  [:phone_home, :phone_mobile, :phone_work, :phone_fax].each do |attr|
    self[attr] = strip_bad_characters(attr)
  end
end

需求2的解决方案很简单:将整个正则表达式封装在\A( )?\Z中,使其成为可选的。然后,您可以摆脱所有的…_is_filled?助手。

票数 2
EN

Code Review用户

发布于 2014-08-15 19:08:41

你可以用一个小小的数组魔法

代码语言:javascript
运行
复制
def clean_phone_numbers
  %w(phone_home phone_mobile phone_work phone_fax).each do |attribute|
    self[attribute.to_sym] = strip_bad_characters(attribute) if send(attribute).present?
  end
end

def phone_provided
  if [phone_home, phone_mobile, phone_work].all?(&:blank?)
    errors.add(:base, "Must provide a phone number")
  end
end
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/60171

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档