我有两个负责属性验证的类:
it.skip('login (return photo)', function(done) { ...
和第二个
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
它们基本相同。我应该使用受保护的实用程序方法从一个类继承它们还是什么?
答案 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 =~ /\A.+@.+\..+\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; /\A.+@.+\..+\z/i end
end
答案 1 :(得分: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; /\A.+@.+\..+\z/i end
end
EachValidator有一个#kind方法,因此它会添加:name或:email作为失败消息,除非被覆盖。然后你可以让i18n根据rails guide中记录的标准级联进行查找。
答案 2 :(得分:0)
为清晰起见,请将它们分开。这些方法足够小,抽象的混淆会使得它更多,而不是更少,显而易见。
如果你开始有3,4,5,6或更多类似的验证器,这种模式开始显而易见,添加抽象可能会使它更容易理解,更改,依赖或删除。