Reputation: 5674
In my applications, there are multiple custom validators that I keep in app/validators and then call in multiple models.
Mostly I do this for regex based validations, things like email, mobiles, etc basically custom data strings that I need to be in a particular format.
For example:
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
record.errors[attribute] << (options[:message] || "is not a valid email format")
end
end
end
class IpValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/
record.errors[attribute] << (options[:message] || "is not a valid IP format")
end
end
end
The downside of this method is that I have a lot of extra files with pretty much the same code which can get annoying in larger applications.
Is there a better way (more DRY) to define regex based validations such that they are reusable across models?
Upvotes: 1
Views: 385
Reputation: 16628
You can make a base class for regexp validation:
class RegexValidator < ActiveModel::EachValidator
def regex_validate_each(regex, err_msg, record, attribute, value)
unless value =~ regex
record.errors[attribute] << (options[:message] || err_msg)
end
end
end
Then subclass it like:
class EmailValidator < RegexValidator
def validate_each(record, attribute, value)
regex_validate_each(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, "is not a valid IP format", record, attribute, value)
end
end
Upvotes: 2