subdomain_router 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +107 -0
- data/LICENSE.txt +20 -0
- data/README.md +160 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/lib/subdomain_router.rb +84 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/subdomain_router_spec.rb +145 -0
- data/subdomain_router.gemspec +66 -0
- metadata +160 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@subdomain_router --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (3.2.3)
|
5
|
+
actionpack (= 3.2.3)
|
6
|
+
mail (~> 2.4.4)
|
7
|
+
actionpack (3.2.3)
|
8
|
+
activemodel (= 3.2.3)
|
9
|
+
activesupport (= 3.2.3)
|
10
|
+
builder (~> 3.0.0)
|
11
|
+
erubis (~> 2.7.0)
|
12
|
+
journey (~> 1.0.1)
|
13
|
+
rack (~> 1.4.0)
|
14
|
+
rack-cache (~> 1.2)
|
15
|
+
rack-test (~> 0.6.1)
|
16
|
+
sprockets (~> 2.1.2)
|
17
|
+
activemodel (3.2.3)
|
18
|
+
activesupport (= 3.2.3)
|
19
|
+
builder (~> 3.0.0)
|
20
|
+
activerecord (3.2.3)
|
21
|
+
activemodel (= 3.2.3)
|
22
|
+
activesupport (= 3.2.3)
|
23
|
+
arel (~> 3.0.2)
|
24
|
+
tzinfo (~> 0.3.29)
|
25
|
+
activeresource (3.2.3)
|
26
|
+
activemodel (= 3.2.3)
|
27
|
+
activesupport (= 3.2.3)
|
28
|
+
activesupport (3.2.3)
|
29
|
+
i18n (~> 0.6)
|
30
|
+
multi_json (~> 1.0)
|
31
|
+
arel (3.0.2)
|
32
|
+
builder (3.0.0)
|
33
|
+
diff-lcs (1.1.3)
|
34
|
+
erubis (2.7.0)
|
35
|
+
git (1.2.5)
|
36
|
+
hike (1.2.1)
|
37
|
+
i18n (0.6.0)
|
38
|
+
jeweler (1.8.3)
|
39
|
+
bundler (~> 1.0)
|
40
|
+
git (>= 1.2.5)
|
41
|
+
rake
|
42
|
+
rdoc
|
43
|
+
journey (1.0.3)
|
44
|
+
json (1.6.6)
|
45
|
+
mail (2.4.4)
|
46
|
+
i18n (>= 0.4.0)
|
47
|
+
mime-types (~> 1.16)
|
48
|
+
treetop (~> 1.4.8)
|
49
|
+
mime-types (1.18)
|
50
|
+
multi_json (1.3.2)
|
51
|
+
polyglot (0.3.3)
|
52
|
+
rack (1.4.1)
|
53
|
+
rack-cache (1.2)
|
54
|
+
rack (>= 0.4)
|
55
|
+
rack-ssl (1.3.2)
|
56
|
+
rack
|
57
|
+
rack-test (0.6.1)
|
58
|
+
rack (>= 1.0)
|
59
|
+
rails (3.2.3)
|
60
|
+
actionmailer (= 3.2.3)
|
61
|
+
actionpack (= 3.2.3)
|
62
|
+
activerecord (= 3.2.3)
|
63
|
+
activeresource (= 3.2.3)
|
64
|
+
activesupport (= 3.2.3)
|
65
|
+
bundler (~> 1.0)
|
66
|
+
railties (= 3.2.3)
|
67
|
+
railties (3.2.3)
|
68
|
+
actionpack (= 3.2.3)
|
69
|
+
activesupport (= 3.2.3)
|
70
|
+
rack-ssl (~> 1.3.2)
|
71
|
+
rake (>= 0.8.7)
|
72
|
+
rdoc (~> 3.4)
|
73
|
+
thor (~> 0.14.6)
|
74
|
+
rake (0.9.2.2)
|
75
|
+
rdoc (3.12)
|
76
|
+
json (~> 1.4)
|
77
|
+
redcarpet (2.1.1)
|
78
|
+
rspec (2.9.0)
|
79
|
+
rspec-core (~> 2.9.0)
|
80
|
+
rspec-expectations (~> 2.9.0)
|
81
|
+
rspec-mocks (~> 2.9.0)
|
82
|
+
rspec-core (2.9.0)
|
83
|
+
rspec-expectations (2.9.1)
|
84
|
+
diff-lcs (~> 1.1.3)
|
85
|
+
rspec-mocks (2.9.0)
|
86
|
+
sprockets (2.1.2)
|
87
|
+
hike (~> 1.2)
|
88
|
+
rack (~> 1.0)
|
89
|
+
tilt (~> 1.1, != 1.3.0)
|
90
|
+
thor (0.14.6)
|
91
|
+
tilt (1.3.3)
|
92
|
+
treetop (1.4.10)
|
93
|
+
polyglot
|
94
|
+
polyglot (>= 0.3.1)
|
95
|
+
tzinfo (0.3.33)
|
96
|
+
yard (0.7.5)
|
97
|
+
|
98
|
+
PLATFORMS
|
99
|
+
ruby
|
100
|
+
|
101
|
+
DEPENDENCIES
|
102
|
+
bundler
|
103
|
+
jeweler
|
104
|
+
rails
|
105
|
+
redcarpet
|
106
|
+
rspec
|
107
|
+
yard
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Tim Morgan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
Subdomain Router
|
2
|
+
================
|
3
|
+
|
4
|
+
A Ruby on Rails addition that adds dynamic subdomain routing to your web app.
|
5
|
+
|
6
|
+
| | |
|
7
|
+
|:------------|:--------------------------------|
|
8
|
+
| **Author** | Tim Morgan |
|
9
|
+
| **Version** | 1.0 (Apr 20, 2012) |
|
10
|
+
| **License** | Released under the MIT license. |
|
11
|
+
|
12
|
+
About
|
13
|
+
-----
|
14
|
+
|
15
|
+
This gem consists of two components: A routing constraint that can be used in
|
16
|
+
your `routes.rb` file to limit certain endpoints to dynamic subdomains (or vice
|
17
|
+
versa), and a monkey-patch to the `url_for` method that allows it to
|
18
|
+
intelligently generate URLs with subdomains.
|
19
|
+
|
20
|
+
The most common use case for this is if you have each of your users choose a
|
21
|
+
subdomain when they sign up, and then you route to different user accounts based
|
22
|
+
on their subdomain. (Think Heroku for example.)
|
23
|
+
|
24
|
+
Sorry about the monkey-patching by the way. :( You should probably inspect the
|
25
|
+
patch closely if you are using any other `url_for` hooks.
|
26
|
+
|
27
|
+
### Testing multiple subdomains in development
|
28
|
+
|
29
|
+
Typically in development you access your website by going to
|
30
|
+
"http://localhost:3000" (or perhaps "http://0.0.0.0:3000"). Neither of these
|
31
|
+
URLs is compatible with subdomains, however.
|
32
|
+
|
33
|
+
Fortunately there exists an easy solution that requires no changes to your
|
34
|
+
`/etc/hosts` file. The domain "lvh.me" points to 127.0.0.1, so by going to
|
35
|
+
"http://lvh.me:3000", you can access your local Rails instance. And it works
|
36
|
+
with subdomains: "http://custom.lvh.me:3000" will work just as well.
|
37
|
+
|
38
|
+
Installation
|
39
|
+
------------
|
40
|
+
|
41
|
+
### Gem installation
|
42
|
+
|
43
|
+
To use this gem, add to your Gemfile:
|
44
|
+
|
45
|
+
```` ruby
|
46
|
+
gem 'subdomain_router'
|
47
|
+
````
|
48
|
+
|
49
|
+
### Configuration
|
50
|
+
|
51
|
+
You will need to configure SubdomainRouter before you can use it. The
|
52
|
+
configuration code can be placed anywhere you feel is appropriate
|
53
|
+
(`config/application.rb`, a file in `config/initializers`, etc.) as long as it
|
54
|
+
runs when your web app starts up.
|
55
|
+
|
56
|
+
```` ruby
|
57
|
+
SubdomainRouter::Config.default_subdomain = 'www'
|
58
|
+
SubdomainRouter::Config.domain = 'mywebsite.com'
|
59
|
+
SubdomainRouter::Config.tld_components = 1
|
60
|
+
SubdomainRouter::Config.subdomain_matcher = ->(subdomain, request) { ... }
|
61
|
+
````
|
62
|
+
|
63
|
+
The configuration options are described below.
|
64
|
+
|
65
|
+
| Option | Description |
|
66
|
+
|:--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
67
|
+
| `default_subdomain` | The subdomain to use when no dynamic subdomain is specified. This is the subdomain people would use when visiting your site for the first time (default "www" and "" for test.) |
|
68
|
+
| `domain` | The domain name. In development, it is by default `lvh.me` (see the _About_ section). In test, it is by default `test.host`. In production, it should be the domain name of your site. |
|
69
|
+
| `tld_components` | The number of components in the TLD. If you have a `.com` website, this is 1. If you have a `.co.uk` website, it would be 2. In development and test, it should be 1 (default 1). |
|
70
|
+
| `subdomain_matcher` | A `Proc` that takes a subdomain (as a `String`) and an `ActionDispatch::Request` object, and returns `true` if it is a valid dynamic subdomain, or `false` otherwise. A response of `false` would result in a 404. |
|
71
|
+
|
72
|
+
So as you can see, sensible defaults are provided for most options. At a
|
73
|
+
minimum, you need to set `subdomain_matcher` in all environments and `domain` in
|
74
|
+
production.
|
75
|
+
|
76
|
+
These configuration variables are shared by some others in Rails. For DRY
|
77
|
+
purposes, you can reuse the configuration values:
|
78
|
+
|
79
|
+
```` ruby
|
80
|
+
Rails.application.config.action_dispatch.tld_length = SubdomainRouter::Config.tld_components
|
81
|
+
|
82
|
+
# if you use cookies
|
83
|
+
Rails.application.config.session_store :cookie_store, domain: ".#{SubdomainRouter::Config.domain}", expire_after: 2.weeks, key: '_mysite_session'
|
84
|
+
````
|
85
|
+
|
86
|
+
### Code additions
|
87
|
+
|
88
|
+
In your `ApplicationController`, add the following:
|
89
|
+
|
90
|
+
```` ruby
|
91
|
+
include SubdomainRouter::Controller
|
92
|
+
````
|
93
|
+
|
94
|
+
In your routes file, group all of the routes you _do_ want to be accessible from
|
95
|
+
dynamic subdomains into a block like so:
|
96
|
+
|
97
|
+
```` ruby
|
98
|
+
constraints SubdomainRouter::Constraint do
|
99
|
+
# [...]
|
100
|
+
end
|
101
|
+
````
|
102
|
+
|
103
|
+
Then group all of the routes you want accessible from the default subdomain into
|
104
|
+
a similar block:
|
105
|
+
|
106
|
+
```` ruby
|
107
|
+
constraints(subdomain: SubdomainRouter::Config.default_subdomain) do
|
108
|
+
# [...]
|
109
|
+
end
|
110
|
+
````
|
111
|
+
|
112
|
+
This should be all you need. See the next section to learn how to use the
|
113
|
+
monkey-patched `url_for`.
|
114
|
+
|
115
|
+
Usage
|
116
|
+
-----
|
117
|
+
|
118
|
+
Aside from implementing the `subdomain_matcher` proc above, the only other thing
|
119
|
+
you will need to is provide subdomain information to all of your links. Since
|
120
|
+
`url_for` powers the URL methods (e.g., `posts_url`), the following information
|
121
|
+
applies to them equally.
|
122
|
+
|
123
|
+
For every call to `link_to` or `url_for` in your views, you will need to think
|
124
|
+
about how the link will work with subdomains. There are three possibilities:
|
125
|
+
|
126
|
+
* **Leave the subdomain untouched.** A link to `/bar` at `www.foo.com` will go
|
127
|
+
to `www.foo.com/bar`. A link to `/bar` at `custom.foo.com` will go to
|
128
|
+
`custom.foo.com/bar`.
|
129
|
+
* **Go to the default subdomain.** A link to `/bar` at `www.foo.com` will go to
|
130
|
+
`www.foo.com/bar`. A link to `/bar` at `custom.foo.com` will go to
|
131
|
+
`www.foo.com/bar`.
|
132
|
+
* **Go to a specific subdomain.** A link to `/bar` at `www.foo.com` will go to
|
133
|
+
`custom.foo.com/bar`. A link to `/bar` at `another.foo.com` will go to
|
134
|
+
`custom.foo.com/bar`.
|
135
|
+
|
136
|
+
So, if you want to **leave the subdomain untouched**, either omit the
|
137
|
+
`:subdomain` option from your call to `url_for`, or set it to `nil`:
|
138
|
+
|
139
|
+
```` ruby
|
140
|
+
url_for(controller: 'posts', action: 'index') # implied subdomain: nil
|
141
|
+
posts_url(subdomain: nil) # explicitly specifying
|
142
|
+
````
|
143
|
+
|
144
|
+
If you want to **go to the default subdomain**, set the `:subdomain` option to
|
145
|
+
`false`:
|
146
|
+
|
147
|
+
```` ruby
|
148
|
+
url_for(controller: 'testimonials', action: 'index', subdomain: false)
|
149
|
+
testimonials_url(subdomain: false)
|
150
|
+
````
|
151
|
+
|
152
|
+
If you want to **go to a specific subdomain**, specify it using the `:subdomain`
|
153
|
+
option:
|
154
|
+
|
155
|
+
```` ruby
|
156
|
+
url_for(controller: 'profile', action: 'show', subdomain: user.subdomain)
|
157
|
+
profile_url(subdomain: user.subdomain)
|
158
|
+
````
|
159
|
+
|
160
|
+
See {SubdomainRouter::Controller#url_for} for more.
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "subdomain_router"
|
18
|
+
gem.homepage = "http://github.com/RISCfuture/subdomain_router"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Use dynamic subdomains in your Rails website}
|
21
|
+
gem.description = %Q{This adds a routing constraint and controller methods to allow dynamic subdomain-based routing.}
|
22
|
+
gem.email = "gemcutter@timothymorgan.info"
|
23
|
+
gem.authors = ["Tim Morgan"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
task default: :spec
|
35
|
+
|
36
|
+
require 'yard'
|
37
|
+
YARD::Rake::YardocTask.new('doc') do |doc|
|
38
|
+
doc.options << '-m' << 'markdown' << '-M' << 'redcarpet'
|
39
|
+
doc.options << '--protected' << '--no-private'
|
40
|
+
doc.options << '-r' << 'README.md'
|
41
|
+
doc.options << '-o' << 'doc'
|
42
|
+
doc.options << '--title' << 'Subdomain Router Documentation'
|
43
|
+
|
44
|
+
doc.files = %w( lib/**/* README.md )
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Module for working with dynamic subdomain routing.
|
2
|
+
|
3
|
+
module SubdomainRouter
|
4
|
+
|
5
|
+
# Controller mixin that adds subdomain management features.
|
6
|
+
|
7
|
+
module Controller
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
helper_method(:url_for) if respond_to?(:helper_method)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds to the `url_for` method the ability to route to different subdomains.
|
15
|
+
# Thus, all URL generation (including smart route methods) gains the
|
16
|
+
# `:subdomain` options.
|
17
|
+
#
|
18
|
+
# For more information, see the Rails documentation.
|
19
|
+
#
|
20
|
+
# @param [Hash] options Options for the URL.
|
21
|
+
# @option options [String, nil, false] :subdomain The subdomain to route to.
|
22
|
+
# If `false`, uses the default subdomain (e.g., "www"). If `nil`, uses the
|
23
|
+
# current subdomain.
|
24
|
+
# @return [String] The generated URL.
|
25
|
+
# @raise [ArgumentError] If the `:subdomain` option is invalid.
|
26
|
+
|
27
|
+
def url_for(options={})
|
28
|
+
return super unless options.is_a?(Hash)
|
29
|
+
|
30
|
+
case options[:subdomain]
|
31
|
+
when nil
|
32
|
+
options.delete :subdomain
|
33
|
+
super options
|
34
|
+
when false, String
|
35
|
+
subdomain = options.delete(:subdomain) || Config.default_subdomain
|
36
|
+
host = options[:host] || (respond_to?(:request) && request.host) || Config.domain
|
37
|
+
host_parts = host.split('.').last(Config.tld_components + 1)
|
38
|
+
host_parts.unshift subdomain
|
39
|
+
host_parts.delete_if &:blank?
|
40
|
+
super options.merge(host: host_parts.join('.'))
|
41
|
+
else
|
42
|
+
raise ArgumentError, ":subdomain must be nil, false, or a string"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# A routing constraint that restricts routes to only valid dynamic subdomains.
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# get 'home' => 'accounts#show', constraint: SubdomainRouter::Constraint
|
51
|
+
|
52
|
+
module Constraint
|
53
|
+
|
54
|
+
# Determines if a given request has a custom user subdomain.
|
55
|
+
#
|
56
|
+
# @param [ActionDispatch::Request] request An HTTP request.
|
57
|
+
# @return [true, false] Whether the request subdomain matches a known user
|
58
|
+
# subdomain.
|
59
|
+
|
60
|
+
def matches?(request)
|
61
|
+
return false unless request.subdomains.size == 1
|
62
|
+
return false if request.subdomains.first == Config.default_subdomain
|
63
|
+
return subdomain?(request)
|
64
|
+
end
|
65
|
+
module_function :matches?
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def subdomain?(request)
|
70
|
+
subdomain = request.subdomains.first.downcase
|
71
|
+
Config.subdomain_matcher.(subdomain, request)
|
72
|
+
end
|
73
|
+
module_function :subdomain?
|
74
|
+
end
|
75
|
+
|
76
|
+
# Subdomain routing configuration object.
|
77
|
+
|
78
|
+
Config = Struct.new(:default_subdomain, :domain, :tld_components, :subdomain_matcher).new
|
79
|
+
Config.default_subdomain = Rails.env.test? ? '' : 'www'
|
80
|
+
Config.domain = 'lvh.me' if Rails.env.development?
|
81
|
+
Config.domain = 'test.host' if Rails.env.test?
|
82
|
+
Config.tld_components = 1
|
83
|
+
Config.subdomain_matcher = ->(subdomain, request) { false }
|
84
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.require :development
|
6
|
+
Bundler.require
|
7
|
+
require 'action_controller'
|
8
|
+
require 'subdomain_router'
|
9
|
+
|
10
|
+
# Requires supporting files with custom matchers and macros, etc,
|
11
|
+
# in ./support/ and its subdirectories.
|
12
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
13
|
+
|
14
|
+
SubdomainRouter::Config.default_subdomain = ''
|
15
|
+
SubdomainRouter::Config.tld_components = 1
|
16
|
+
SubdomainRouter::Config.domain = 'test.host'
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class UrlForController < ActionController::Metal
|
4
|
+
include SubdomainRouter::Controller
|
5
|
+
end
|
6
|
+
|
7
|
+
class UrlForMailer
|
8
|
+
include SubdomainRouter::Controller
|
9
|
+
end
|
10
|
+
|
11
|
+
describe SubdomainRouter::Controller do
|
12
|
+
before :all do
|
13
|
+
@controller = UrlForController.new
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#url_for" do
|
17
|
+
it "should call the superclass unless a hash is given" do
|
18
|
+
@controller.url_for('foo').should eql('foo')
|
19
|
+
end
|
20
|
+
|
21
|
+
context "[given host]" do
|
22
|
+
before :each do
|
23
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'test.host'))
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should leave the domain untouched if :subdomain => nil" do
|
27
|
+
@controller.url_for(host: 'foo.bar').should eql(host: 'foo.bar')
|
28
|
+
@controller.url_for(host: 'sd.foo.bar').should eql(host: 'sd.foo.bar')
|
29
|
+
@controller.url_for(host: 'baz.bat.foo.bar').should eql(host: 'baz.bat.foo.bar')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should replace the subdomain if :subdomain is given" do
|
33
|
+
@controller.url_for(host: 'foo.bar', subdomain: 'sd').should eql(host: 'sd.foo.bar')
|
34
|
+
@controller.url_for(host: 'baz.foo.bar', subdomain: 'sd').should eql(host: 'sd.foo.bar')
|
35
|
+
@controller.url_for(host: 'baz.bat.foo.bar', subdomain: 'sd').should eql(host: 'sd.foo.bar')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should use the default subdomain if :subdomain is false" do
|
39
|
+
@controller.url_for(host: 'foo.bar', subdomain: false).should eql(host: 'foo.bar')
|
40
|
+
@controller.url_for(host: 'baz.foo.bar', subdomain: false).should eql(host: 'foo.bar')
|
41
|
+
@controller.url_for(host: 'baz.bat.foo.bar', subdomain: false).should eql(host: 'foo.bar')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "[request host]" do
|
46
|
+
it "should leave the domain untouched if :subdomain => nil" do
|
47
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'foo.bar'))
|
48
|
+
@controller.url_for(subdomain: nil).should eql({})
|
49
|
+
|
50
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'sd.foo.bar'))
|
51
|
+
@controller.url_for(subdomain: nil).should eql({})
|
52
|
+
|
53
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'baz.bat.foo.bar'))
|
54
|
+
@controller.url_for(subdomain: nil).should eql({})
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should replace the subdomain if :subdomain is given" do
|
58
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'foo.bar'))
|
59
|
+
@controller.url_for(subdomain: 'sd').should eql(host: 'sd.foo.bar')
|
60
|
+
|
61
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'baz.foo.bar'))
|
62
|
+
@controller.url_for(subdomain: 'sd').should eql(host: 'sd.foo.bar')
|
63
|
+
|
64
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'baz.bat.foo.bar'))
|
65
|
+
@controller.url_for(subdomain: 'sd').should eql(host: 'sd.foo.bar')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should use the default subdomain if :subdomain is false" do
|
69
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'foo.bar'))
|
70
|
+
@controller.url_for(subdomain: false).should eql(host: 'foo.bar')
|
71
|
+
|
72
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'baz.foo.bar'))
|
73
|
+
@controller.url_for(subdomain: false).should eql(host: 'foo.bar')
|
74
|
+
|
75
|
+
@controller.stub!(:request).and_return(mock('ActionDispatch::Request', host: 'baz.bat.foo.bar'))
|
76
|
+
@controller.url_for(subdomain: false).should eql(host: 'foo.bar')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "[no host]" do
|
81
|
+
before :all do
|
82
|
+
@mailer = UrlForMailer.new
|
83
|
+
end
|
84
|
+
|
85
|
+
before :each do
|
86
|
+
pending "Need to find a way to test this without building up a whole Rails app"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should leave the domain untouched if :subdomain => nil" do
|
90
|
+
# no host provided = exception
|
91
|
+
-> { @mailer.url_for(controller: 'users', action: 'new', subdomain: nil) }.should raise_error(ArgumentError)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should replace the subdomain if :subdomain is given" do
|
95
|
+
@mailer.url_for(controller: 'users', action: 'new', subdomain: 'sd').should eql('http://sd.test.host/users/new')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should use the default subdomain if :subdomain is false" do
|
99
|
+
@mailer.url_for(controller: 'users', action: 'new', subdomain: false).should eql('http://test.host/users/new')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe SubdomainRouter::Constraint do
|
106
|
+
describe ".matches?" do
|
107
|
+
before :each do
|
108
|
+
@env = {}
|
109
|
+
@request = mock('ActionDispatch::Request', env: @env)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should return false if there is more than one subdomain" do
|
113
|
+
@request.stub!(:subdomains).and_return(%w( foo bar ))
|
114
|
+
SubdomainRouter::Constraint.matches?(@request).should be_false
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should return false if there is no subdomain" do
|
118
|
+
@request.stub!(:subdomains).and_return([])
|
119
|
+
SubdomainRouter::Constraint.matches?(@request).should be_false
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should return false if the subdomain is equal to the default subdomain" do
|
123
|
+
SubdomainRouter::Config.default_subdomain = 'www'
|
124
|
+
@request.stub!(:subdomains).and_return(%w( www ))
|
125
|
+
SubdomainRouter::Constraint.matches?(@request).should be_false
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should return false if the subdomain does not belong to any user" do
|
129
|
+
@request.stub!(:subdomains).and_return(%w( not-found ))
|
130
|
+
SubdomainRouter::Constraint.matches?(@request).should be_false
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should return true if the subdomain belongs to a user and save the user to the env" do
|
134
|
+
SubdomainRouter::Config.subdomain_matcher = ->(subdomain, request) { subdomain == 'valid' }
|
135
|
+
@request.stub!(:subdomains).and_return([ 'valid' ])
|
136
|
+
SubdomainRouter::Constraint.matches?(@request).should be_true
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should downcase the subdomain" do
|
140
|
+
SubdomainRouter::Config.subdomain_matcher = ->(subdomain, request) { subdomain == 'valid' }
|
141
|
+
@request.stub!(:subdomains).and_return([ 'VALID' ])
|
142
|
+
SubdomainRouter::Constraint.matches?(@request).should be_true
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "subdomain_router"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Tim Morgan"]
|
12
|
+
s.date = "2012-04-23"
|
13
|
+
s.description = "This adds a routing constraint and controller methods to allow dynamic subdomain-based routing."
|
14
|
+
s.email = "gemcutter@timothymorgan.info"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"lib/subdomain_router.rb",
|
30
|
+
"spec/spec_helper.rb",
|
31
|
+
"spec/subdomain_router_spec.rb"
|
32
|
+
]
|
33
|
+
s.homepage = "http://github.com/RISCfuture/subdomain_router"
|
34
|
+
s.licenses = ["MIT"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = "1.8.23"
|
37
|
+
s.summary = "Use dynamic subdomains in your Rails website"
|
38
|
+
|
39
|
+
if s.respond_to? :specification_version then
|
40
|
+
s.specification_version = 3
|
41
|
+
|
42
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
43
|
+
s.add_runtime_dependency(%q<rails>, [">= 0"])
|
44
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
45
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
46
|
+
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
49
|
+
else
|
50
|
+
s.add_dependency(%q<rails>, [">= 0"])
|
51
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
52
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
53
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
54
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
55
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
56
|
+
end
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<rails>, [">= 0"])
|
59
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
60
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
61
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
62
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
63
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: subdomain_router
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Morgan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: yard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: redcarpet
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: jeweler
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: This adds a routing constraint and controller methods to allow dynamic
|
111
|
+
subdomain-based routing.
|
112
|
+
email: gemcutter@timothymorgan.info
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files:
|
116
|
+
- LICENSE.txt
|
117
|
+
- README.md
|
118
|
+
files:
|
119
|
+
- .document
|
120
|
+
- .rspec
|
121
|
+
- .rvmrc
|
122
|
+
- Gemfile
|
123
|
+
- Gemfile.lock
|
124
|
+
- LICENSE.txt
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- VERSION
|
128
|
+
- lib/subdomain_router.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/subdomain_router_spec.rb
|
131
|
+
- subdomain_router.gemspec
|
132
|
+
homepage: http://github.com/RISCfuture/subdomain_router
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
hash: -4479704525159209868
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 1.8.23
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: Use dynamic subdomains in your Rails website
|
160
|
+
test_files: []
|