ruby-on-rails ruby regex validation url

ruby on rails - Rieles: ¿Cuál es una buena forma de validar enlaces(URL)?



ruby-on-rails regex (18)

Me preguntaba cómo mejor validaría las URL en Rails. Estaba pensando en usar una expresión regular, pero no estoy seguro de si esta es la mejor práctica.

Y, si tuviera que usar una expresión regular, ¿alguien podría sugerirme una? Todavía soy nuevo en Regex.


Aquí hay una versión actualizada del validador publicado por David James . Ha sido publicado por Benjamin Fleischer . Mientras tanto, empujé una horquilla actualizada que se puede encontrar here .

require ''addressable/uri'' # Source: http://gist.github.com/bf4/5320847 # Accepts options[:message] and options[:allowed_protocols] # spec/validators/uri_validator_spec.rb class UriValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) uri = parse_uri(value) if !uri record.errors[attribute] << generic_failure_message elsif !allowed_protocols.include?(uri.scheme) record.errors[attribute] << "must begin with #{allowed_protocols_humanized}" end end private def generic_failure_message options[:message] || "is an invalid URL" end def allowed_protocols_humanized allowed_protocols.to_sentence(:two_words_connector => '' or '') end def allowed_protocols @allowed_protocols ||= [(options[:allowed_protocols] || [''http'', ''https''])].flatten end def parse_uri(value) uri = Addressable::URI.parse(value) uri.scheme && uri.host && uri rescue URI::InvalidURIError, Addressable::URI::InvalidURIError, TypeError end end

...

require ''spec_helper'' # Source: http://gist.github.com/bf4/5320847 # spec/validators/uri_validator_spec.rb describe UriValidator do subject do Class.new do include ActiveModel::Validations attr_accessor :url validates :url, uri: true end.new end it "should be valid for a valid http url" do subject.url = ''http://www.google.com'' subject.valid? subject.errors.full_messages.should == [] end [''http://google'', ''http://.com'', ''http://ftp://ftp.google.com'', ''http://ssh://google.com''].each do |invalid_url| it "#{invalid_url.inspect} is a invalid http url" do subject.url = invalid_url subject.valid? subject.errors.full_messages.should == [] end end [''http:/www.google.com'',''<>hi''].each do |invalid_url| it "#{invalid_url.inspect} is an invalid url" do subject.url = invalid_url subject.valid? subject.errors.should have_key(:url) subject.errors[:url].should include("is an invalid URL") end end [''www.google.com'',''google.com''].each do |invalid_url| it "#{invalid_url.inspect} is an invalid url" do subject.url = invalid_url subject.valid? subject.errors.should have_key(:url) subject.errors[:url].should include("is an invalid URL") end end [''ftp://ftp.google.com'',''ssh://google.com''].each do |invalid_url| it "#{invalid_url.inspect} is an invalid url" do subject.url = invalid_url subject.valid? subject.errors.should have_key(:url) subject.errors[:url].should include("must begin with http or https") end end end

Tenga en cuenta que todavía hay URI HTTP extraños que se analizan como direcciones válidas.

http://google http://.com http://ftp://ftp.google.com http://ssh://google.com

Aquí hay un problema para la gema addressable que cubre los ejemplos.


Esta pregunta ya está respondida, pero qué diablos, propongo la solución que estoy usando.

La expresión regular funciona bien con todas las direcciones URL que he conocido. El método setter es cuidar si no se menciona ningún protocolo (supongamos http: //).

Y finalmente, intentamos buscar la página. Tal vez debería aceptar redirecciones y no solo HTTP 200 OK.

# app/models/my_model.rb validates :website, :allow_blank => true, :uri => { :format => /(^$)|(^(http|https):////[a-z0-9]+([/-/.]{1}[a-z0-9]+)*/.[a-z]{2,5}(([0-9]{1,5})?//.*)?$)/ix } def website= url_str unless url_str.blank? unless url_str.split('':'')[0] == ''http'' || url_str.split('':'')[0] == ''https'' url_str = "http://" + url_str end end write_attribute :website, url_str end

y...

# app/validators/uri_vaidator.rb require ''net/http'' # Thanks Ilya! http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/ # Original credits: http://blog.inquirylabs.com/2006/04/13/simple-uri-validation/ # HTTP Codes: http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTPResponse.html class UriValidator < ActiveModel::EachValidator def validate_each(object, attribute, value) raise(ArgumentError, "A regular expression must be supplied as the :format option of the options hash") unless options[:format].nil? or options[:format].is_a?(Regexp) configuration = { :message => I18n.t(''errors.events.invalid_url''), :format => URI::regexp(%w(http https)) } configuration.update(options) if value =~ configuration[:format] begin # check header response case Net::HTTP.get_response(URI.parse(value)) when Net::HTTPSuccess then true else object.errors.add(attribute, configuration[:message]) and false end rescue # Recover on DNS failures.. object.errors.add(attribute, configuration[:message]) and false end else object.errors.add(attribute, configuration[:message]) and false end end end


He estado usando la gema "validadores activos" y funciona bastante bien (no solo para la validación de URL)

puedes encontrarlo here

Está todo documentado, pero básicamente una vez que la gema se agrega, querrás agregar las siguientes líneas en un inicializador, por ejemplo: /config/environments/initializers/active_validators_activation.rb

# Activate all the validators ActiveValidators.activate(:all)

(Nota: puede reemplazar: all by: url o: lo que sea si solo quiere validar tipos específicos de valores)

Y luego regresa a tu modelo algo como esto

class Url < ActiveRecord::Base validates :url, :presence => true, :url => true end

Ahora reinicie el servidor y eso debería ser


La solución que funcionó para mí fue:

validates_format_of :url, :with => //A(https?:////)?([/da-z/.-]+)/.([a-z/.]{2,6})([///w/.-]*)*//?/Z/i

Intenté usar algunos de los ejemplos que adjuntó, pero estoy soportando la URL de esta manera:

Observe el uso de A y Z porque si usa ^ y $ verá esta advertencia de seguridad de los validadores de Rails.

Valid ones: ''www.crowdint.com'' ''crowdint.com'' ''http://crowdint.com'' ''http://www.crowdint.com'' Invalid ones: ''http://www.crowdint. com'' ''http://fake'' ''http:fake''


La validación de URL no se puede manejar simplemente mediante el uso de una expresión regular, ya que la cantidad de sitios web sigue creciendo y siguen surgiendo nuevos esquemas de nombres de dominio.

En mi caso, simplemente escribo un validador personalizado que busca una respuesta exitosa.

class UrlValidator < ActiveModel::Validator def validate(record) begin url = URI.parse(record.path) response = Net::HTTP.get(url) true if response.is_a?(Net::HTTPSuccess) rescue StandardError => error record.errors[:path] << ''Web address is invalid'' false end end end

Estoy validando el atributo de path de mi modelo usando record.path . También estoy empujando el error al nombre de atributo respectivo usando record.errors[:path] .

Simplemente puede reemplazar esto con cualquier nombre de atributo.

Luego, simplemente llamo al validador personalizado en mi modelo.

class Url < ApplicationRecord # validations validates_presence_of :path validates_with UrlValidator end


Me encontré con el mismo problema últimamente (necesitaba validar URL en una aplicación Rails) pero tuve que lidiar con el requisito adicional de las URL unicode (por ejemplo, http://кц.рф ) ...

Investigué un par de soluciones y encontré lo siguiente:


Puede validar varias URL usando algo como:

validates_format_of [:field1, :field2], with: URI.regexp([''http'', ''https'']), allow_nil: true


Puedes usar regex para esto, para mí funciona bien este:

(^|[/s.:;?/-/]</(])(ftp|https?:////[-/w;//?:@&=+$/|/_.!~*/|''()/[/]%#,]+[/w//#](/(/))?)(?=$|[/s'',/|/(/).:;?/-/[/]>/)])


Recientemente tuve este mismo problema y encontré una solución alternativa para las URL válidas.

validates_format_of :url, :with => URI::regexp(%w(http https)) validate :validate_url def validate_url unless self.url.blank? begin source = URI.parse(self.url) resp = Net::HTTP.get_response(source) rescue URI::InvalidURIError errors.add(:url,''is Invalid'') rescue SocketError errors.add(:url,''is Invalid'') end end

La primera parte del método validate_url es suficiente para validar el formato url. La segunda parte se asegurará de que exista la url mediante el envío de una solicitud.


Siguiendo la idea de Simone, puede crear fácilmente su propio validador.

class UrlValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return if value.blank? begin uri = URI.parse(value) resp = uri.kind_of?(URI::HTTP) rescue URI::InvalidURIError resp = false end unless resp == true record.errors[attribute] << (options[:message] || "is not an url") end end end

y luego usa

validates :url, :presence => true, :url => true

en tu modelo.


Solo mis 2 centavos:

before_validation :format_website validate :website_validator private def format_website self.website = "http://#{self.website}" unless self.website[/^https?/] end def website_validator errors[:website] << I18n.t("activerecord.errors.messages.invalid") unless website_valid? end def website_valid? !!website.match(/^(https?:////)?([/da-z/.-]+)/.([a-z/.]{2,6})([///w /.-=/?]*)*//?$/) end

EDITAR: cambio de expresiones regulares para que coincida con las URL de los parámetros.


También hay validate_url gem (que es solo un buen contenedor para la solución de Addressable::URI.parse ).

Solo agrega

gem ''validate_url''

a tu Gemfile , y luego en los modelos que puedas

validates :click_through_url, url: true


También puede probar la valid_url gem que permite URLs sin el esquema, comprueba la zona de dominio y los nombres de host de IP.

Agrégalo a tu Gemfile:

gem ''valid_url''

Y luego en el modelo:

class WebSite < ActiveRecord::Base validates :url, :url => true end


Uso un trazador de líneas dentro de mis modelos:

validates :url, :format => URI::regexp(%w(http https))

Creo que es lo suficientemente bueno y simple de usar. Además, debería ser teóricamente equivalente al método de Simone, ya que utiliza la misma expresión regular internamente.


Utilizo una ligera variación en la solución de lafeber anterior . No permite puntos consecutivos en el nombre de host (como por ejemplo en www.many...dots.com ):

%r"/A(https?://)?[a-z/d/-]+(/.[a-z/d/-]+)*/.[a-z]{2,6}(/.*)?/Z"i

URI.parse parece URI.parse de esquema, que en algunos casos no es lo que puede desear (por ejemplo, si desea permitir a los usuarios escribir rápidamente las URL en formularios como twitter.com/username )


Validar una URL es un trabajo complicado. También es una solicitud muy amplia.

¿Qué quieres hacer, exactamente? ¿Desea validar el formato de la URL, la existencia o qué? Hay varias posibilidades, dependiendo de lo que quieras hacer.

Una expresión regular puede validar el formato de la URL. Pero incluso una expresión regular compleja no puede garantizar que se trata de una URL válida.

Por ejemplo, si toma una expresión regular simple, probablemente rechazará el siguiente host

http://invalid##host.com

pero permitirá

http://invalid-host.foo

es un host válido, pero no válido si considera los TLD existentes. De hecho, la solución funcionaría si desea validar el nombre de host, no el dominio porque el siguiente es un nombre de host válido

http://host.foo

también el siguiente

http://localhost

Ahora, déjame darte algunas soluciones.

Si desea validar un dominio, debe olvidarse de las expresiones regulares. La mejor solución disponible en este momento es la Lista de sufijos públicos, una lista mantenida por Mozilla. PublicSuffix una biblioteca de Ruby para analizar y validar dominios en contra de la Lista de sufijos públicos, y se llama PublicSuffix .

Si desea validar el formato de un URI / URL, entonces quizás quiera usar expresiones regulares. En lugar de buscar uno, use el método Ruby URI.parse .

require ''uri'' def valid_url?(uri) uri = URI.parse(uri) && !uri.host.nil? rescue URI::InvalidURIError false end

Incluso puede decidir hacerlo más restrictivo. Por ejemplo, si desea que la URL sea una URL HTTP / HTTPS, puede hacer que la validación sea más precisa.

require ''uri'' def valid_url?(url) uri = URI.parse(url) uri.is_a?(URI::HTTP) && !uri.host.nil? rescue URI::InvalidURIError false end

Por supuesto, hay muchas mejoras que puede aplicar a este método, incluida la comprobación de una ruta o un esquema.

Por último, pero no menos importante, también puede empaquetar este código en un validador:

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


Y como un módulo

module UrlValidator extend ActiveSupport::Concern included do validates :url, presence: true, uniqueness: true validate :url_format end def url_format begin errors.add(:url, "Invalid url") unless URI(self.url).is_a?(URI::HTTP) rescue URI::InvalidURIError errors.add(:url, "Invalid url") end end end

Y luego solo include UrlValidator en cualquier modelo para el que quieras validar url''s. Solo incluyendo opciones.