Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

email validation added and url validation improved

  • Loading branch information...
commit 66fa41b3c894eb7defeade24817d4ed42c36f92a 1 parent e384f5a
Molte Emil Strange Andersen authored September 11, 2009
31  lib/acts_as_url.rb
@@ -8,9 +8,10 @@ def self.included(base)
8 8
   self.default_protocols = %w( http https )
9 9
   
10 10
   module ClassMethods
11  
-    URL_SUBDOMAINS_PATTERN = '(?:[-\w]+\.)+'
12  
-    URL_TLD_PATTERN        = '[a-z]{2,6}'
  11
+    URL_SUBDOMAINS_PATTERN = '(?:[a-z0-9-]+\.)+'
  12
+    URL_TLD_PATTERN        = '(?:[a-z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
13 13
     URL_PORT_PATTERN       = '(?::\d{1,5})?'
  14
+    EMAIL_NAME_PATTERN     = '[\w.%+-]+'
14 15
     
15 16
     attr_accessor :protocols
16 17
     
@@ -22,7 +23,7 @@ def acts_as_url(*attributes)
22 23
         # Set default protocols
23 24
         self.protocols[attribute] ||= ActsAsUrl.default_protocols
24 25
         
25  
-        add_url_validation(attribute, self.protocols[attribute].to_a)
  26
+        validates_url(attribute, :protocols => self.protocols[attribute].to_a)
26 27
         
27 28
         # Define before save callback
28 29
         callback_name = "convert_#{attribute}_to_url".to_sym
@@ -47,9 +48,22 @@ def url.to_uri
47 48
       send(:include, InstanceMethods)
48 49
     end
49 50
     
50  
-    private
51  
-    def add_url_validation(attribute, protocols)
52  
-      validates_format_of(attribute, :with => /\A(?:(?:#{protocols.join('|')}):\/\/)?#{URL_SUBDOMAINS_PATTERN + URL_TLD_PATTERN + URL_PORT_PATTERN}(?:\/\S*)?\z/, :allow_blank => true)
  51
+    protected
  52
+    def validates_url(*attr_names)
  53
+      options          = attr_names.extract_options!
  54
+      protocol_pattern = "(?:(?:#{ (options.delete(:protocols) || ActsAsUrl.default_protocols).map { |p| ActsAsUrl.escape_regex p } * '|' }):\/\/)?"
  55
+      port_pattern     = options[:ports] ? "(?: :#{ options.delete(:ports).map { |p| ActsAsUrl.escape_regex p } * '|' } )" : URL_PORT_PATTERN
  56
+      
  57
+      validates_format_of(*attr_names << { :allow_blank => true,
  58
+        :with => /\A #{protocol_pattern + URL_SUBDOMAINS_PATTERN + URL_TLD_PATTERN + port_pattern} (?:\/\S*)? \z/ix }.merge(options))
  59
+    end
  60
+    
  61
+    def validates_email(*attr_names)
  62
+      options = attr_names.extract_options!
  63
+      
  64
+      validates_format_of(*attr_names << { :allow_blank => true,
  65
+        # Regex inspired by rick olson's restful-authentication plugin
  66
+        :with => /\A #{EMAIL_NAME_PATTERN} @ #{URL_SUBDOMAINS_PATTERN + URL_TLD_PATTERN} \z/ix }.merge(options))
53 67
     end
54 68
     
55 69
   end
@@ -84,4 +98,9 @@ def url_without_protocol(url, protocol)
84 98
     
85 99
   end
86 100
   
  101
+  # Escapes all regular expression tokens in a given string.
  102
+  def self.escape_regex(regex_str)
  103
+    regex_str.to_s.gsub(/[[\\^$.|?*+()\/]/) { |token_char| '\\' + token_char[0] }
  104
+  end
  105
+  
87 106
 end
56  test/acts_as_url_test.rb
@@ -5,53 +5,91 @@ class ActsAsUrlTest < Test::Unit::TestCase # ActiveSupport::TestCase
5 5
   
6 6
   class Item < ActiveRecord::Base
7 7
     acts_as_url :website, :repository => 'git'
  8
+    validates_url :second_website, :ports => [ 80, 8080 ]
  9
+    validates_email :email
8 10
   end
9 11
   
10 12
   def test_schema_has_loaded_correctly
11 13
     assert_not_nil Item.all
12 14
   end
13 15
   
14  
-  # Validation tests
15  
-  def test_validation_when_no_protocol_or_path
  16
+  # Url validation tests
  17
+  def test_url_validation_when_no_protocol_or_path
16 18
     @item.website = 'example.com'
17 19
     assert @item.valid?
18 20
   end
19 21
   
20  
-  def test_validation_when_no protocol_but_path
  22
+  def test_url_validation_when_no_protocol_but_path
21 23
     @item.website = 'example.info/directory/page.html?query=true&still=true#hash'
22 24
     assert @item.valid?
23 25
   end
24 26
   
25  
-  def test_validation_when_protocol
  27
+  def test_url_validation_when_protocol
26 28
     @item.website = 'https://example.com/'
27 29
     assert @item.valid?
28 30
   end
29 31
   
30  
-  def test_validation_when_subdomains
  32
+  def test_url_validation_when_subdomains
31 33
     @item.website = 'dk.subdomain.example.net'
32 34
     assert @item.valid?
33 35
   end
34 36
   
35  
-  def test_validation_when_port
  37
+  def test_url_validation_when_port
36 38
     @item.website = 'http://example.com:8080/'
37 39
     assert @item.valid?
38 40
   end
39 41
   
40  
-  def test_validation_when_no_tld
  42
+  def test_url_validation_when_no_tld
41 43
     @item.website = 'example'
42 44
     assert @item.invalid?
43 45
   end
44 46
   
45  
-  def test_validation_when_wrong_protocol
  47
+  def test_url_validation_when_wrong_tld
  48
+    @item.website = 'example.abc'
  49
+    assert @item.invalid?
  50
+  end
  51
+  
  52
+  def test_url_validation_when_wrong_protocol
46 53
     @item.website = 'ftp://example.com/'
47 54
     assert @item.invalid?
48 55
   end
49 56
   
50  
-  def test_validation_when_blank
  57
+  def test_url_validation_when_blank
51 58
     @item.website = ''
52 59
     assert @item.valid?
53 60
   end
54 61
   
  62
+  def test_url_validation_when_wrong_port
  63
+    @item.second_website = 'example.com:123'
  64
+    assert @item.invalid?
  65
+  end
  66
+  
  67
+  # Email validation tests
  68
+  def test_email_validation_when_no_name
  69
+    @item.email = '@example.com'
  70
+    assert @item.invalid?
  71
+  end
  72
+  
  73
+  def test_email_validation_when_no_at
  74
+    @item.email = 'nameexample.com'
  75
+    assert @item.invalid?
  76
+  end
  77
+  
  78
+  def test_email_validation_when_invalid_domain
  79
+    @item.email = 'name@in!valid.com'
  80
+    assert @item.invalid?
  81
+  end
  82
+  
  83
+  def test_email_validation_when_subdomains
  84
+    @item.email = 'name@sub.example.com'
  85
+    assert @item.valid?
  86
+  end
  87
+  
  88
+  def test_email_validation_when_blank
  89
+    @item.email = ''
  90
+    assert @item.valid?
  91
+  end
  92
+  
55 93
   # Convertion tests
56 94
   def test_default_convertion
57 95
     @item.website = 'example.com'
2  test/schema.rb
@@ -2,5 +2,7 @@
2 2
   create_table :items, :force => true do |t|
3 3
     t.string :website
4 4
     t.string :repository
  5
+    t.string :email
  6
+    t.string :second_website
5 7
   end
6 8
 end

0 notes on commit 66fa41b

Please sign in to comment.
Something went wrong with that request. Please try again.