Skip to content

Instantly share code, notes, and snippets.

@joshuap
Created April 29, 2011 19:37
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save joshuap/948880 to your computer and use it in GitHub Desktop.
Save joshuap/948880 to your computer and use it in GitHub Desktop.
Net:HTTP enabled URI Validator for Rails 3
...
require 'uri_validator'
validates :url, :presence => true, :uri => { :format => /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix }
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 => "is invalid or not responding", :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
@chrisbloom7
Copy link

An updated format: /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?([\/].*)?$)/ix

Most importantly it fixes an error in the original in which the colon before the port number was missing. It also allows for URLs that don't include a / after the domain (i.e. http://www.google.com)

@Krule
Copy link

Krule commented Jul 8, 2011

This validation will fail if site redirects and returns 30X. Some sites use 30X in order to redirect to some inner page.

irb(main):001:0> v = "http://siemens.com"
=> "http://siemens.com"
irb(main):002:0> Net::HTTP.get_response(URI.parse(v))
=> #<Net::HTTPMovedPermanently 301 Moved Permanently readbody=true>

Easily fixable by changing line 16 to:

when Net::HTTPSuccess, Net::HTTPRedirection then true

@valk
Copy link

valk commented Jul 4, 2012

This doesn't seem to work. Tried with http://google.com, http://www.google.com, http://google.com/. Also tried to apply the other 2 guys comments. No luck?

@joshuap
Copy link
Author

joshuap commented Jul 13, 2012

@valk works for me:

irb(main):006:0> r = /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?([\/].*)?$)/ix
=> /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?([\/].*)?$)/ix
irb(main):007:0> r =~ 'http://google.com'                                   => 0
irb(main):008:0> r =~ 'http://www.google.com'
=> 0
irb(main):009:0> r =~ 'http://google.com/'
=> 0
irb(main):010:0> 

@Server4001
Copy link

No support for ftp://.... ?

@joshuap
Copy link
Author

joshuap commented Jul 17, 2013

@Server4001 you could easily add support to the regex for ftp://. Something like:

validates :url, :presence => true, :uri => { :format => URI::regexp(%w(http https ftp)) }

However, I think the Net::HTTP request would fail for FTP uris. You would need to modify the validator to check the validity of the FTP server.

@BeenaShetty
Copy link

Enter only url i.e http://www.flipkart.com then it doesnot validate it. It should also check if it is not a proper image url

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment