HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyrailsMinor

Classes for attributes validation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
attributesvalidationforclasses

Problem

I have two classes responsible for attributes validation:

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


and the second one:

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 =~ /\A.+@.+\..+\z/i
  end
end


They're basically the same. Should I inherit them from one class with protected utility methods or what?

Solution

By creating a base class and then inheriting from it, you end up with no duplication and with an architecture that can be easily extended.

I don't think that you should bother having valid? as protected. Calling valid? from outside is a common use case and doesn't violate encapsulation.

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

  def self.valid?(value)
    raise NotImplementedError
  end
end

class NameValidator < Validator
  def self.valid?(value)
    value =~ /\A[a-z][\w\p{Blank}]+\z/i
  end
end

class EmailValidator < Validator
  def self.valid?(value)
    value =~ /\A.+@.+\..+\z/i
  end
end

Code Snippets

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

  def self.valid?(value)
    raise NotImplementedError
  end
end

class NameValidator < Validator
  def self.valid?(value)
    value =~ /\A[a-z][\w\p{Blank}]+\z/i
  end
end

class EmailValidator < Validator
  def self.valid?(value)
    value =~ /\A.+@.+\..+\z/i
  end
end

Context

StackExchange Code Review Q#117885, answer score: 5

Revisions (0)

No revisions yet.