Skip to content

Instantly share code, notes, and snippets.

@chrisbloom7
Forked from joshuap/environment.rb
Last active December 20, 2015 10:30
Show Gist options
  • Save chrisbloom7/6115329 to your computer and use it in GitHub Desktop.
Save chrisbloom7/6115329 to your computer and use it in GitHub Desktop.
ActiveRecord validator for URLs
require 'uri_validator'
class SomeModel < ActiveRecord::Base
validates :url, :presence => true, :uri => { :format => /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?([\/].*)?$)/ix }
end
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
TIMEOUT_IN_SECONDS = 4
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
Rack::MiniProfiler.step("UriValidator with http.head") do
uri = URI.parse(value)
http = Net::HTTP.new(uri.host, uri.port)
http.continue_timeout = TIMEOUT_IN_SECONDS
http.open_timeout = TIMEOUT_IN_SECONDS
http.read_timeout = TIMEOUT_IN_SECONDS
if uri.scheme == "https"
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.ssl_timeout = TIMEOUT_IN_SECONDS
end
case http.head(uri.request_uri)
when Net::HTTPSuccess, Net::HTTPRedirection then true
else object.errors.add(attribute, configuration[:message]) and false
end
end
rescue # Recover on DNS or timeout failures..
object.errors.add(attribute, configuration[:message]) and false
end
else
object.errors.add(attribute, configuration[:message]) and false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment