La validation d'une URL est une tâche délicate. C'est aussi une demande très large.
Que voulez-vous faire exactement? Voulez-vous valider le format de l'URL, l'existence ou quoi? Il existe plusieurs possibilités, selon ce que vous souhaitez faire.
Une expression régulière peut valider le format de l'URL. Mais même une expression régulière complexe ne peut garantir que vous avez affaire à une URL valide.
Par exemple, si vous prenez une expression régulière simple, elle rejettera probablement l'hôte suivant
http://invalid##host.com
mais cela permettra
http://invalid-host.foo
c'est un hôte valide, mais pas un domaine valide si vous considérez les TLD existants. En effet, la solution fonctionnerait si vous souhaitez valider le nom d'hôte, pas le domaine car le suivant est un nom d'hôte valide
http://host.foo
ainsi que le suivant
http://localhost
Maintenant, laissez-moi vous donner quelques solutions.
Si vous souhaitez valider un domaine, vous devez oublier les expressions régulières. La meilleure solution disponible pour le moment est la Public Suffix List, une liste maintenue par Mozilla. J'ai créé une bibliothèque Ruby pour analyser et valider les domaines par rapport à la liste de suffixes publics, et elle s'appelle PublicSuffix .
Si vous souhaitez valider le format d'un URI / URL, vous pouvez utiliser des expressions régulières. Au lieu d'en rechercher un, utilisez la URI.parse
méthode Ruby intégrée .
require 'uri'
def valid_url?(uri)
uri = URI.parse(uri) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
Vous pouvez même décider de le rendre plus restrictif. Par exemple, si vous souhaitez que l'URL soit une URL HTTP / HTTPS, vous pouvez rendre la validation plus précise.
require 'uri'
def valid_url?(url)
uri = URI.parse(url)
uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
Bien sûr, il existe des tonnes d'améliorations que vous pouvez appliquer à cette méthode, notamment la vérification d'un chemin ou d'un schéma.
Enfin, vous pouvez également regrouper ce code dans un validateur:
class HttpUrlValidator < ActiveModel::EachValidator
def self.compliant?(value)
uri = URI.parse(value)
uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
def validate_each(record, attribute, value)
unless value.present? && self.class.compliant?(value)
record.errors.add(attribute, "is not a valid HTTP URL")
end
end
end
# in the model
validates :example_attribute, http_url: true