projectdx-subdomain_routes 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ module SubdomainRoutes
2
+ def self.valid_subdomain?(subdomain)
3
+ subdomain.to_s =~ /^([a-z]|[a-z][a-z0-9]|[a-z]([a-z0-9]|\-[a-z0-9])*)$/
4
+ end
5
+
6
+ # # Alternatively, we use URI::parse instead. This gives more lenient subdomains however:
7
+ # def self.valid_subdomain?(subdomain)
8
+ # URI.parse "http://#{subdomain}.example.com"
9
+ # rescue URI::InvalidURIError
10
+ # false
11
+ # end
12
+
13
+ module Validations
14
+ module ClassMethods
15
+ def validates_subdomain_format_of(*attr_names)
16
+ configuration = { :on => :save }
17
+ configuration.update(attr_names.extract_options!)
18
+
19
+ validates_each(attr_names, configuration) do |record, attr_name, value|
20
+ unless SubdomainRoutes.valid_subdomain?(value)
21
+ record.errors.add(attr_name, :not_a_valid_subdomain, :default => configuration[:message], :value => value)
22
+ end
23
+ end
24
+ end
25
+
26
+ def validates_subdomain_not_reserved(*attr_names)
27
+ configuration = { :on => :save }
28
+ configuration.update(attr_names.extract_options!)
29
+
30
+ validates_each(attr_names, configuration) do |record, attr_name, value|
31
+ if ActionController::Routing::Routes.reserved_subdomains.include? value
32
+ record.errors.add(attr_name, :is_a_reserved_subdomain, :default => configuration[:message], :value => value)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ if defined? ActiveRecord::Base
41
+ ActiveRecord::Base.send :extend, SubdomainRoutes::Validations::ClassMethods
42
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'subdomain_routes'
@@ -0,0 +1,193 @@
1
+ require 'test/unit/testresult'
2
+ require 'spec_helper'
3
+
4
+ class HomesController < ActionController::Base
5
+ end
6
+
7
+ describe "routing assertions" do
8
+ context "for single-subdomain route" do
9
+ before(:each) do
10
+ map_subdomain :admin, :name => nil do |admin|
11
+ admin.resource :home
12
+ end
13
+ @options = { :controller => "homes", :action => "show", :subdomains => [ "admin" ] }
14
+ end
15
+
16
+ context "recognition" do
17
+ it "should correctly succeed with a :host option and a subdomain route" do
18
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "admin.example.com" }) }
19
+ test.should_not have_errors
20
+ test.should_not fail
21
+ end
22
+
23
+ it "should correctly fail with a :host option and a subdomain route" do
24
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "www.example.com" } ) }
25
+ test.should have_errors
26
+ end
27
+ end
28
+
29
+ context "generation" do
30
+ it "should correctly succeed with :host and :path options and a subdomain route which changes the subdomain and no subdomain is specified" do
31
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "admin.example.com" }, @options, "www.example.com") }
32
+ test.should_not have_errors
33
+ test.should_not fail
34
+ end
35
+
36
+ it "should correctly fail with :host and :path options and a subdomain route which changes the subdomain and the wrong subdomain is specified" do
37
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "admin.example.com" }, @options.merge(:subdomain => "other"), "www.example.com") }
38
+ test.should have_errors
39
+ end
40
+
41
+ it "should correctly fail with :host and :path options and a subdomain route which changes the subdomain and the correct subdomain is specified" do
42
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "admin.example.com" }, @options.merge(:subdomain => "admin"), "www.example.com") }
43
+ test.should_not have_errors
44
+ test.should_not fail
45
+ end
46
+
47
+ it "should correctly fail with :host and :path options and a subdomain route which doesn't change the subdomain" do
48
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "admin.example.com" }, @options, "admin.example.com") }
49
+ test.should_not have_errors
50
+ test.should fail
51
+ end
52
+
53
+ it "should correctly succeed with a path and a subdomain route which doesn't change the subdomain" do
54
+ test = lambda { assert_generates_with_host("/home", @options, "admin.example.com") }
55
+ test.should_not have_errors
56
+ test.should_not fail
57
+ end
58
+
59
+ it "should correctly fail with a path and a subdomain route which changes the subdomain" do
60
+ test = lambda { assert_generates_with_host("/home", @options, "www.example.com") }
61
+ test.should_not have_errors
62
+ test.should fail
63
+ end
64
+ end
65
+ end
66
+
67
+ context "for multiple-subdomain route" do
68
+ before(:each) do
69
+ @subdomains = [ "admin", "support" ]
70
+ map_subdomain *(@subdomains + [ { :name => nil } ]) do |media|
71
+ media.resource :home
72
+ end
73
+ @options = { :controller => "homes", :action => "show", :subdomains => @subdomains }
74
+ end
75
+
76
+ context "recognition" do
77
+ it "should correctly succeed with a :host option and a subdomain route" do
78
+ @subdomains.each do |subdomain|
79
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "#{subdomain}.example.com" }) }
80
+ test.should_not have_errors
81
+ test.should_not fail
82
+ end
83
+ end
84
+
85
+ it "should correctly fail with a :host option and a subdomain route" do
86
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "www.example.com" } ) }
87
+ test.should have_errors
88
+ end
89
+ end
90
+
91
+ context "generation" do
92
+ it "should correctly fail with :host and :path options and a subdomain route which changes the subdomain and no subdomain is specified" do
93
+ @subdomains.each do |subdomain|
94
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "#{subdomain}.example.com" }, @options, "www.example.com") }
95
+ test.should have_errors
96
+ end
97
+ end
98
+
99
+ it "should correctly fail with :host and :path options and a subdomain route which changes the subdomain and the wrong subdomain is specified" do
100
+ @subdomains.each do |subdomain|
101
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "#{subdomain}.example.com" }, @options.merge(:subdomain => "other"), "www.example.com") }
102
+ test.should have_errors
103
+ end
104
+ end
105
+
106
+ it "should correctly succeed with :host and :path options and a subdomain route which changes the subdomain and a correct subdomain is specified" do
107
+ @subdomains.each do |subdomain|
108
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "#{subdomain}.example.com" }, @options.merge(:subdomain => subdomain), "www.example.com") }
109
+ test.should_not have_errors
110
+ test.should_not fail
111
+ end
112
+ end
113
+
114
+ it "should correctly fail with :host and :path options and a subdomain route which doesn't change the subdomain" do
115
+ @subdomains.each do |subdomain|
116
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "#{subdomain}.example.com" }, @options, "#{subdomain}.example.com") }
117
+ test.should_not have_errors
118
+ test.should fail
119
+ end
120
+ end
121
+
122
+ it "should correctly succeed with a path and a subdomain route which doesn't change the subdomain" do
123
+ @subdomains.each do |subdomain|
124
+ test = lambda { assert_generates_with_host("/home", @options, "#{subdomain}.example.com") }
125
+ test.should_not have_errors
126
+ test.should_not fail
127
+ end
128
+ end
129
+
130
+ it "should correctly fail with a path and a subdomain route which changes the subdomain" do
131
+ @subdomains.each do |subdomain|
132
+ test = lambda { assert_generates_with_host("/home", @options.merge(:subdomain => subdomain), "www.example.com") }
133
+ test.should_not have_errors
134
+ test.should fail
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ context "for model-based subdomain route" do
141
+ before(:each) do
142
+ map_subdomain :model => :city, :namespace => nil do |city|
143
+ city.resource :home
144
+ end
145
+ @options = { :controller => "homes", :action => "show", :subdomains => :city_id, :city_id => "canberra" }
146
+ end
147
+
148
+ context "recognition" do
149
+ it "should correctly succeed with a :host option and a subdomain route" do
150
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "canberra.example.com" }) }
151
+ test.should_not have_errors
152
+ test.should_not fail
153
+ end
154
+
155
+ it "should correctly fail with a :host option and a subdomain route for the wrong subdomain" do
156
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "boston.example.com" }) }
157
+ test.should_not have_errors
158
+ test.should fail
159
+ end
160
+
161
+ it "should correctly fail with a :host option and a subdomain route for no subdomain" do
162
+ test = lambda { assert_recognizes_with_host(@options, { :path => "/home", :host => "example.com" }) }
163
+ test.should have_errors
164
+ end
165
+ end
166
+
167
+ context "generation" do
168
+ it "should correctly succeed with :host and :path options and a subdomain route which changes the subdomain" do
169
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "canberra.example.com" }, @options, "boston.example.com") }
170
+ test.should_not have_errors
171
+ test.should_not fail
172
+ end
173
+
174
+ it "should correctly fail with :host and :path options and a subdomain route which doesn't change the subdomain" do
175
+ test = lambda { assert_generates_with_host({ :path => "/home", :host => "canberra.example.com" }, @options, "canberra.example.com") }
176
+ test.should_not have_errors
177
+ test.should fail
178
+ end
179
+
180
+ it "should correctly succeed with :host and :path options and a subdomain route which doesn't change the subdomain" do
181
+ test = lambda { assert_generates_with_host("/home", @options, "canberra.example.com") }
182
+ test.should_not have_errors
183
+ test.should_not fail
184
+ end
185
+
186
+ it "should correctly fail with :host and :path options and a subdomain route which changes the subdomain" do
187
+ test = lambda { assert_generates_with_host("/home", @options, "www.example.com") }
188
+ test.should_not have_errors
189
+ test.should fail
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe "subdomain extraction" do
4
+ include SubdomainRoutes::SplitHost
5
+
6
+ it "should add a subdomain method to requests" do
7
+ request = ActionController::TestRequest.new
8
+ request.host = "admin.example.com"
9
+ request.subdomain.should == "admin"
10
+ end
11
+
12
+ it "should raise an error if no host is supplied" do
13
+ lambda { split_host(nil) }.should raise_error(SubdomainRoutes::HostNotSupplied)
14
+ end
15
+
16
+ context "when the domain length is not set" do
17
+ before(:each) do
18
+ SubdomainRoutes::Config.stub!(:domain_length).and_return(nil)
19
+ end
20
+
21
+ it "should always find a subdomain and a domain" do
22
+ split_host("example.com").should == [ "example", "com" ]
23
+ split_host("www.example.com").should == [ "www", "example.com" ]
24
+ split_host("blah.www.example.com").should == [ "blah", "www.example.com" ]
25
+ end
26
+
27
+ it "should raise an error if a nil subdomain is mapped" do
28
+ lambda { map_subdomain(nil) }.should raise_error(ArgumentError)
29
+ lambda { map_subdomain(nil, :www) }.should raise_error(ArgumentError)
30
+ end
31
+ end
32
+
33
+ context "when domain length is set" do
34
+ before(:each) do
35
+ SubdomainRoutes::Config.stub!(:domain_length).and_return(2)
36
+ end
37
+
38
+ it "should find the domain" do
39
+ domain_for_host("www.example.com").should == "example.com"
40
+ end
41
+
42
+ it "should find the subdomain when it is present" do
43
+ subdomain_for_host("www.example.com").should == "www"
44
+ end
45
+
46
+ it "should return an empty string when subdomain is absent" do
47
+ subdomain_for_host("example.com").should == ""
48
+ end
49
+
50
+ context "and multi-level subdomains are found" do
51
+ before(:each) do
52
+ @host = "blah.www.example.com"
53
+ end
54
+
55
+ it "should raise an error" do
56
+ lambda { subdomain_for_host(@host) }.should raise_error(SubdomainRoutes::TooManySubdomains)
57
+ end
58
+
59
+ it "should raise an error when generating URLs" do
60
+ map_subdomain(:admin) { |admin| admin.resources :users }
61
+ with_host(@host) do
62
+ lambda { admin_users_path }.should raise_error(SubdomainRoutes::TooManySubdomains)
63
+ end
64
+ end
65
+
66
+ it "should raise an error when recognising URLs" do
67
+ request = ActionController::TestRequest.new
68
+ request.host = @host
69
+ lambda { recognize_path(request) }.should raise_error(SubdomainRoutes::TooManySubdomains)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe "subdomain route mapping" do
4
+ it "should check the validity of each subdomain" do
5
+ SubdomainRoutes.should_receive(:valid_subdomain?).twice.and_return(true, true)
6
+ lambda { map_subdomain(:www, :www1) { } }.should_not raise_error
7
+ end
8
+
9
+ it "should check the validity of each subdomain and raise an error if any are invalid" do
10
+ SubdomainRoutes.should_receive(:valid_subdomain?).twice.and_return(true, false)
11
+ lambda { map_subdomain(:www, :www!) { } }.should raise_error(ArgumentError)
12
+ end
13
+
14
+ it "should check not the validity of a nil subdomain" do
15
+ SubdomainRoutes.should_not_receive(:valid_subdomain?)
16
+ map_subdomain(nil) { }
17
+ end
18
+
19
+ it "should accept a nil subdomain" do
20
+ map_subdomain(nil) { |map| map.options[:subdomains].should == [ "" ] }
21
+ end
22
+
23
+ it "should accept a blank subdomain" do
24
+ map_subdomain("") { |map| map.options[:subdomains].should == [ "" ] }
25
+ end
26
+
27
+ it "should accept a single specified subdomain" do
28
+ map_subdomain(:admin) { |admin| admin.options[:subdomains].should == [ "admin" ] }
29
+ end
30
+
31
+ it "should accept strings or symbols as subdomains" do
32
+ map_subdomain(:admin) { |admin| admin.options[:subdomains].should == [ "admin" ] }
33
+ map_subdomain("admin") { |admin| admin.options[:subdomains].should == [ "admin" ] }
34
+ end
35
+
36
+ it "should accept multiple subdomains" do
37
+ map_subdomain(:admin, :support) { |map| map.options[:subdomains].should == [ "admin", "support" ] }
38
+ end
39
+
40
+ it "should downcase the subdomains" do
41
+ map_subdomain(:Admin, "SUPPORT") { |map| map.options[:subdomains].should == [ "admin", "support" ] }
42
+ end
43
+
44
+ it "should raise ArgumentError if a nil :model option is specified as the subdomain" do
45
+ lambda { map_subdomain(:model => "") { } }.should raise_error(ArgumentError)
46
+ end
47
+
48
+ it "should raise ArgumentError if no subdomain is specified" do
49
+ lambda { map_subdomain }.should raise_error(ArgumentError)
50
+ end
51
+
52
+ it "should not include repeated subdomains in the options" do
53
+ map_subdomain(:admin, :support, :admin) { |map| map.options[:subdomains].should == [ "admin", "support" ] }
54
+ end
55
+
56
+ it "should be invoked by map.subdomains as well as map.subdomain" do
57
+ ActionController::Routing::Routes.draw do |map|
58
+ map.subdomains(:admin, :support) { |sub| sub.options[:subdomains].should == [ "admin", "support" ] }
59
+ end
60
+ end
61
+
62
+ [ [ :admin ], [ :support, :admin ] ].each do |subdomains|
63
+ context "mapping #{subdomains.size} subdomains" do
64
+ it "should set the first subdomain as a namespace" do
65
+ map_subdomain(*subdomains) { |map| map.options[:namespace].should == "#{subdomains.first}/" }
66
+ end
67
+
68
+ it "should prefix the first subdomain to named routes" do
69
+ map_subdomain(*subdomains) { |map| map.options[:name_prefix].should == "#{subdomains.first}_" }
70
+ end
71
+
72
+ it "should instead set a namespace to the name if specified" do
73
+ args = subdomains + [ :name => :something ]
74
+ map_subdomain(*args) { |map| map.options[:namespace].should == "something/" }
75
+ end
76
+
77
+ it "should instead prefix the name to named routes if specified" do
78
+ args = subdomains + [ :name => :something ]
79
+ map_subdomain(*args) { |map| map.options[:name_prefix].should == "something_" }
80
+ end
81
+
82
+ it "should not set a namespace if name is specified as nil" do
83
+ args = subdomains + [ :name => nil ]
84
+ map_subdomain(*args) { |map| map.options[:namespace].should be_nil }
85
+ end
86
+
87
+ it "should not set a named route prefix if name is specified as nil" do
88
+ args = subdomains + [ :name => nil ]
89
+ map_subdomain(*args) { |map| map.options[:name_prefix].should be_nil }
90
+ end
91
+ end
92
+ end
93
+
94
+ it "should strip bad characters from the namespace and name prefix" do
95
+ map_subdomain("just-do-it") { |map| map.options[:namespace].should == "just_do_it/" }
96
+ map_subdomain("just-do-it") { |map| map.options[:name_prefix].should == "just_do_it_" }
97
+ map_subdomain(nil, :name => "just-do-it") { |map| map.options[:namespace].should == "just_do_it/" }
98
+ map_subdomain(nil, :name => "just-do-it") { |map| map.options[:name_prefix].should == "just_do_it_" }
99
+ map_subdomain(nil, :name => "Just do it!") { |map| map.options[:namespace].should == "just_do_it/" }
100
+ map_subdomain(nil, :name => "Just do it!") { |map| map.options[:name_prefix].should == "just_do_it_" }
101
+ end
102
+
103
+ context "mapping the nil subdomain" do
104
+ it "should not set a namespace" do
105
+ [ nil, "" ].each do |none|
106
+ map_subdomain(none) { |map| map.options[:namespace].should be_nil }
107
+ end
108
+ end
109
+
110
+ it "should not set a named route prefix" do
111
+ [ nil, "" ].each do |none|
112
+ map_subdomain(none) { |map| map.options[:name_prefix].should be_nil }
113
+ end
114
+ end
115
+ end
116
+
117
+ context "mapping nil and other subdomains" do
118
+ it "should set the first non-nil subdomain as a namespace" do
119
+ [ nil, "" ].each do |none|
120
+ map_subdomain(none, :www) { |map| map.options[:namespace].should == "www/" }
121
+ end
122
+ end
123
+
124
+ it "should prefix the first non-nil subdomain to named routes" do
125
+ [ nil, "" ].each do |none|
126
+ map_subdomain(none, :www) { |map| map.options[:name_prefix].should == "www_" }
127
+ end
128
+ end
129
+ end
130
+
131
+ context "for a :model subdomain" do
132
+ it "should accept a :model option as the subdomain and turn it into a foreign key symbol" do
133
+ map_subdomain(:model => :city) { |city| city.options[:subdomains].should == :city_id }
134
+ end
135
+
136
+ it "should singularize a plural model name" do
137
+ map_subdomain(:model => :cities) { |city| city.options[:subdomains].should == :city_id }
138
+ end
139
+
140
+ it "should accept a string model name" do
141
+ map_subdomain(:model => "city") { |city| city.options[:subdomains].should == :city_id }
142
+ end
143
+
144
+ it "should set the model name as a namespace" do
145
+ map_subdomain(:model => :city) { |city| city.options[:namespace].should == "city/" }
146
+ end
147
+
148
+ it "should prefix the model name to named routes" do
149
+ map_subdomain(:model => :city) { |city| city.options[:name_prefix].should == "city_" }
150
+ end
151
+
152
+ it "should instead set a namespace to the name if specified" do
153
+ map_subdomain(:model => :city, :name => :something) { |map| map.options[:namespace].should == "something/" }
154
+ end
155
+
156
+ it "should instead prefix the name to named routes if specified" do
157
+ map_subdomain(:model => :city, :name => :something) { |map| map.options[:name_prefix].should == "something_" }
158
+ end
159
+
160
+ it "should not set a namespace if name is specified as nil" do
161
+ map_subdomain(:model => :city, :name => nil) { |map| map.options[:namespace].should be_nil }
162
+ end
163
+
164
+ it "should not set a named route prefix if name is specified as nil" do
165
+ map_subdomain(:model => :city, :name => nil) { |map| map.options[:name_prefix].should be_nil }
166
+ end
167
+ end
168
+ end