2016-01-25 29 views
0

之间不必要的重复,我有责任属性验证两类:减少两班

class NameValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    message = options.fetch(:message, I18n.t('errors.attributes.name.invalid')) 
    record.errors[attribute] << message unless NameValidator.valid_name?(value) 
    end 

    def self.valid_name?(name) 
    name =~ /\A[a-z][\w\p{Blank}]+\z/i 
    end 
end 

,第二个

class EmailValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    message = options.fetch(:message, I18n.t('errors.attributes.email.invalid')) 
    record.errors[attribute] << message unless EmailValidator.valid_email?(value) 
    end 

    def self.valid_email?(email) 
    email =~ /\[email protected]+\..+\z/i 
    end 
end 

,他们基本上是相同的。我应该使用受保护的实用方法从一个类继承它们吗?

+0

恕我直言,这将是一个很好的问题http://codereview.stackexchange.com/ –

回答

1

可以简化这一进一步

class PatternValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    message = options.fetch(:message) || kind 
    record.errors[attribute] << message unless value =~ validation_pattern 
    end 
end 

class NameValidator < PatternValidator 
    def validation_pattern; /\A[a-z][\w\p{Blank}]+\z/i end 
end 

class EmailValidator < PatternValidator 
    def validation_pattern; /\[email protected]+\..+\z/i end 
end 

EachValidator有#因此它会添加:name或:email作为失败消息,除非被覆盖。然后,您可以让国际化域名按照rails guide中记录的标准级联进行查找。

+0

这是美丽的,谢谢。 –

0

为了清晰起见,请将它们保持分开。这些方法足够小,因为抽象的混淆会让事情变得更多而不是更不明显。

如果您开始有3,4,5,6个或更多类似的验证器,其中此模式开始显而易见,则添加抽象可能会使其更易于理解,更改,依赖或移除。

+0

这就是事情,有更多的验证工具在我的项目中提取。邮政标题验证,例如.. –

+0

如何使用内置的ActiveModel格式验证程序? http://edgeguides.rubyonrails.org/active_record_validations.html#format – Glenn

+0

不,我提取这个验证器,以避免这种情况 –

1

只有当一个类明显是另一个类的特例时才使用继承。在你的例子中,这两个类似乎是平等的。然后,使用mixin,而不是继承。

代码中反对通用validate_each的一个小点是NameValidator.valid_name?EmailValidator.valid_email?的硬编码。你需要在两个类中使用的通用代码中使它们相同。首先,你不需要给出不同的名字valid_name?valid_email?。他们的差异应该通过使用相应的类来吸收。使用通用名称。其次,您不需要对接收器进行硬编码。相反,使用self.class。但不是使用类方法来实现,而是使用实例方法。

module ValidatorModule 
    def validate_each(record, attribute, value) 
    message = options.fetch(:message, I18n.t("errors.attributes.#{attribute}.invalid")) 
    record.errors[attribute] << message unless valid?(value) 
    end 
end 

class NameValidator < ActiveModel::EachValidator 
    include ValidatorModule 
    def attribute; "name" end 
    def valid?(value); value =~ /\A[a-z][\w\p{Blank}]+\z/i end 
end 

class EmailValidator < ActiveModel::EachValidator 
    include ValidatorModule 
    def attribute; "email" end 
    def valid?(value); value =~ /\[email protected]+\..+\z/i end 
end 

如果你认为验证总是有一个简单的正则表达式完成,你可以走一步:

module ValidatorModule 
    def validate_each(record, attribute, value) 
    message = options.fetch(:message, I18n.t("errors.attributes.#{attribute}.invalid")) 
    record.errors[attribute] << message unless value =~ validation_pattern 
    end 
end 

class NameValidator < ActiveModel::EachValidator 
    include ValidatorModule 
    def attribute; "name" end 
    def validation_pattern; /\A[a-z][\w\p{Blank}]+\z/i end 
end 

class EmailValidator < ActiveModel::EachValidator 
    include ValidatorModule 
    def attribute; "email" end 
    def validation_pattern; /\[email protected]+\..+\z/i end 
end