我有一个复杂的电话验证,它执行以下操作:
下面是我实现上述三个步骤的方式:
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?的属性。我怎么才能重构这个呢?
发布于 2014-08-15 19:09:19
让我们总结一下业务规则:
!或x以外的字符将被删除。需求3是由validate :phone_provided处理的,它简单而精细。
这种不满来自于实现需求1和2。
通过使strip_bad_characters()能够容忍nil,可以简化需求1的实现。您也可以调用#read_attribute_before_type_cast()以避免插值。
def strip_bad_characters(attr)
input = read_attribute_before_type_cast(attr)
input.gsub(/[^\d+!x]/, '') if input
end此外,clean_phone_numbers()还可以使用循环:
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?助手。
发布于 2014-08-15 19:08:41
你可以用一个小小的数组魔法
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
endhttps://codereview.stackexchange.com/questions/60171
复制相似问题