Skip to content
Newer
Older
100644 161 lines (119 sloc) 6.38 KB
9dca953 @RISCfuture Initial commit to subdomain_router.
authored Apr 20, 2012
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.
Something went wrong with that request. Please try again.