projectdx-subdomain_routes 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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