Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Exhaustive list of supported validators and their implementation:
* `ssn` : Social Security Number (only for USA).
* `tracking_number`: based on a set of predefined masks
* `twitter` : based on a regular expression
* `url` : based on a regular expression
* `url` : based on [`Addressable`](https://github.com/sporkmonger/addressable) gem


### Handling error messages
Expand Down
1 change: 1 addition & 0 deletions activevalidators.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Gem::Specification.new do |s|
s.add_dependency 'rake'
s.add_dependency 'mail'
s.add_dependency 'date_validator'
s.add_dependency 'addressable' , '~> 2.7'
s.add_dependency 'activemodel' , '>= 3.0'
s.add_dependency 'phony' , '~> 2.0'
s.add_dependency 'countries' , '>= 1.2', '< 4.0'
Expand Down
18 changes: 5 additions & 13 deletions lib/active_validators/active_model/validations/url_validator.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
require 'active_support/core_ext/array/wrap'
require 'uri'
require 'addressable'

module ActiveModel
module Validations

# Public: Uses `URI.regexp` to validate URLs, by default only allows
# Public: Uses `Addressable::URI.parse` to validate URLs, by default only allows
# the http and https protocols.
#
# Examples
Expand Down Expand Up @@ -46,7 +46,7 @@ def initialize(options)
def validate_each(record, attribute, value)
uri = as_uri(value)
tld_requirement_fullfilled = check_tld_requirement(value)
record.errors.add(attribute) unless uri && value.to_s =~ uri_regexp && tld_requirement_fullfilled
record.errors.add(attribute) unless uri && uri.scheme.in?(protocols) && tld_requirement_fullfilled
end

private
Expand All @@ -68,22 +68,14 @@ def protocols
Array.wrap(options[:protocols] || %w{http https})
end

# Internal: Constructs the regular expression to check
# the URI for the configured protocols.
#
# Returns the Regexp.
def uri_regexp
@uri_regexp ||= /\A#{URI::Parser.new.make_regexp(protocols)}\z/
end

# Internal: Checks if the tld requirements are fullfilled
#
# When :require_tld option is set to true, the url will be searched for
# a dot anywhere inside the host except the first or last position
#
# Returns a boolean value.
def check_tld_requirement(value)
host = URI.parse(value.to_s).host rescue value
host = Addressable::URI.parse(value.to_s).host rescue value
options[:require_tld] === true ? host =~ /.(\.)\w+/ : true
end

Expand All @@ -92,7 +84,7 @@ def check_tld_requirement(value)
#
# Returns the URI or nil.
def as_uri(value)
URI.parse(value.to_s) rescue nil if value.present?
Addressable::URI.parse(value.to_s) rescue nil if value.present?
end
end
end
Expand Down
19 changes: 17 additions & 2 deletions test/validations/url_test.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'test_helper'

ActiveValidators.activate(:url)

describe "Url Validation" do
Expand Down Expand Up @@ -49,6 +50,20 @@ def build_ftp_record
_(subject.errors.size).must_equal(0)
end

it "accepts valid urls with non-ascii domain name" do
subject = build_url_record
subject.url = 'https://www.詹姆斯.com'
_(subject.valid?).must_equal(true)
_(subject.errors.size).must_equal(0)
end

it "accepts valid urls with non-ascii path" do
subject = build_url_record
subject.url = 'https://www.example.com/ουτοπία'
_(subject.valid?).must_equal(true)
_(subject.errors.size).must_equal(0)
end

it "accepts ftp if defined" do
subject = build_ftp_record
subject.url = 'ftp://ftp.verrot.fr'
Expand All @@ -67,7 +82,7 @@ def build_ftp_record
describe "for invalid urls" do
it "rejects invalid urls" do
subject = build_url_record
subject.url = 'http://^^^^.fr'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http://^^^^.fr is considered valid by Addressable, which strictly adheres to the RFC. Spaces are not allowed though.

subject.url = 'http://in va lid.fr'
_(subject.valid?).must_equal(false)
_(subject.errors.size).must_equal(1)
end
Expand All @@ -81,7 +96,7 @@ def build_ftp_record

it "generates an error message of type invalid" do
subject = build_url_record
subject.url = 'http://^^^^.fr'
subject.url = 'http://in va lid.fr'
_(subject.valid?).must_equal(false)
_(subject.errors[:url].include?(subject.errors.generate_message(:url, :invalid))).must_equal(true)
end
Expand Down