subdomainitis 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ Copyright (c) 2010 Stephen Judkins
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+ 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
9
+
10
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Subdomainitis: easily and transparently use subdomains as parameters in a Rails 3 application
2
+
3
+ ### Installation and usage
4
+ To install, add `gem "subdomainitis"` to your `Gemfile`. Then modify your routes.rb file; see the example below for usage.
5
+
6
+ MyProject::Application.routes.draw do
7
+ extend Subdomainitis
8
+
9
+ resources :spams
10
+
11
+ main_domain do
12
+ resource :foos
13
+ end
14
+
15
+ subdomain_as(:account) do
16
+ resources :bars
17
+ end
18
+
19
+ use_fake_subdomains! unless Rails.env.production?
20
+ end
21
+
22
+ In the example above, the routes for `spams` will work regardless of the presence of a subdomain. However, the `foos` routes will only work if accessed WITHOUT using a subdomain; only `http://mycompany.com/foos` will work.
23
+
24
+ Accessing `bars` routes will only work when a subdomain is provided. Additionally, the specific subdomain is passed into the controller as a path parameter, as specified by the first argument to `subdomain_as`. For example, `http://subdomain.mycompany.com/bars` resolves to `{:controller => 'bars', :action => 'index', :account => 'subdomain'}`.
25
+
26
+ URL generation should work transparently as well; make sure you're using url instead of path generation (ie, `foos_url` instead of `foos_path`). Subdomainitis tries to fail fast by raising exceptions when a working URL cannot be generated.
27
+
28
+ Call `use_fake_subdomains!` to use the `_subdomain` GET parameter instead of an actual subdomain. This is useful for development where wildcard subdomains aren't possible, or for testing environments like Cucumber that don't support subdomains. This support has been tested with both recognition and generation.
29
+
30
+ No changes are necessary in the controllers.
31
+
32
+ ### Issues
33
+ Though this library seems to work fine for me, there are probably bugs and untested corner cases. Currently only named routes have been verified to work.
34
+
35
+ The implementation could probably be cleaner, and relies on internal Rails APIs that may be change in future versions.
@@ -0,0 +1,135 @@
1
+ module Subdomainitis
2
+
3
+ SUBDOMAIN_KEY = "_subdomain"
4
+
5
+ class IsSubdomain
6
+ def initialize(route_set)
7
+ @route_set = route_set
8
+ end
9
+ attr_reader :route_set
10
+
11
+ def matches?(request)
12
+ if route_set.use_fake_subdomains
13
+ request.GET.has_key?(SUBDOMAIN_KEY)
14
+ else
15
+ request.subdomain.present?
16
+ end
17
+ end
18
+ end
19
+
20
+ class IsMaindomain < IsSubdomain
21
+ def matches?(request)
22
+ !super(request)
23
+ end
24
+ end
25
+
26
+
27
+ class SubdomainRouteSet < ActionDispatch::Routing::RouteSet
28
+ def initialize(parent_route_set, subdomain_key)
29
+ @parent_route_set, @subdomain_key = parent_route_set, subdomain_key
30
+ super *[]
31
+ end
32
+ attr_reader :parent_route_set, :subdomain_key
33
+
34
+ def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
35
+ parent_route_set.add_subdomain_route(name, subdomain_key)
36
+ parent_route_set.add_route wrap(app), conditions, requirements, defaults, name, anchor
37
+ end
38
+
39
+ def wrap(app)
40
+ ActionDispatch::Routing::Mapper::Constraints.new(
41
+ RouteSetMiddleware.new(parent_route_set, app, subdomain_key),
42
+ [IsSubdomain.new(parent_route_set)],
43
+ request_class
44
+ )
45
+ end
46
+ end
47
+
48
+ def subdomain_as(subdomain_key, &block)
49
+ @set.subdomain_routes ||= {}
50
+ subdomain_routeset = SubdomainRouteSet.new @set, subdomain_key
51
+ subdomain_routeset.draw &block
52
+ end
53
+
54
+ def main_domain(&block)
55
+ constraints IsMaindomain.new(@set), &block
56
+ end
57
+
58
+ def use_fake_subdomains!
59
+ @set.use_fake_subdomains = true
60
+ end
61
+
62
+ class RouteSetMiddleware
63
+ def initialize(route_set, dispatcher, subdomain_key)
64
+ @route_set, @dispatcher, @subdomain_key = route_set, dispatcher, subdomain_key
65
+ end
66
+
67
+ attr_reader :route_set, :subdomain_key, :dispatcher
68
+
69
+ PATH_PARAMETER_KEY = 'action_dispatch.request.path_parameters'
70
+
71
+ def call(env)
72
+ request = ActionDispatch::Request.new env
73
+
74
+ path_parameters = env[PATH_PARAMETER_KEY].merge(subdomain_key => subdomain_from(request))
75
+ env = env.merge(PATH_PARAMETER_KEY => path_parameters)
76
+
77
+ dispatcher.call(env)
78
+ end
79
+
80
+ def subdomain_from(request)
81
+ if route_set.use_fake_subdomains
82
+ request.GET[SUBDOMAIN_KEY]
83
+ else
84
+ request.subdomain
85
+ end
86
+ end
87
+ end
88
+
89
+ module RouteSetMethods
90
+ def url_for_with_subdomains(args)
91
+ if subdomain_key = subdomain_routes[args[:use_route]]
92
+ subdomain_url_for(subdomain_key, args.dup)
93
+ else
94
+ url_for_without_subdomains args
95
+ end
96
+ end
97
+
98
+ def subdomain_url_for(subdomain_key, args)
99
+ raise HostRequired.new if args[:only_path]
100
+ subdomain_parameter = args.delete(subdomain_key)
101
+ raise HostRequired.new unless subdomain_parameter
102
+
103
+ url_for_without_subdomains(if use_fake_subdomains
104
+ args.merge SUBDOMAIN_KEY => subdomain_parameter
105
+ else
106
+ args.merge :host => host_name(subdomain_parameter, args[:host])
107
+ end)
108
+ end
109
+
110
+ def add_subdomain_route(name, subdomain_key)
111
+ subdomain_routes[name] = subdomain_key
112
+ end
113
+
114
+ def host_name(subdomain_parameter, host)
115
+ raise HostRequired.new unless host
116
+ ([subdomain_parameter] + host.split(".")[-2..-1]).join(".")
117
+ end
118
+
119
+ end
120
+
121
+ def self.extended(router)
122
+ router.instance_variable_get(:@set).class_eval do
123
+ include RouteSetMethods
124
+ alias_method_chain :url_for, :subdomains
125
+ attr_accessor :subdomain_routes, :use_fake_subdomains
126
+ end
127
+ end
128
+
129
+ class HostRequired < Exception
130
+ def initialize
131
+ super("A hostname must be specified to generate this URL since it depends on a subdomain")
132
+ end
133
+ end
134
+
135
+ end
@@ -0,0 +1,51 @@
1
+ module Subdomainitis
2
+ module SpecHelpers
3
+ extend RSpec::Matchers::DSL
4
+
5
+ define :generate_url do |expected|
6
+
7
+ match do |args|
8
+ generate(args) == expected
9
+ end
10
+
11
+ failure_message_for_should do |args|
12
+ "expected that #{generate(args).inspect} would be == #{expected.inspect}"
13
+ end
14
+
15
+ end
16
+
17
+ define :resolve_to do |expected|
18
+ match do |path|
19
+ called = false
20
+ uri = URI.parse(path)
21
+ controller_class = "#{expected[:controller].camelize}Controller".constantize
22
+ controller_instance = mock(controller_class)
23
+ controller_class.should_receive(:action).any_number_of_times.with(expected[:action]).and_return(controller_instance)
24
+
25
+ controller_instance.should_receive(:call) do |env|
26
+ env["action_dispatch.request.path_parameters"].symbolize_keys.should == expected.symbolize_keys
27
+
28
+ called = true
29
+
30
+ [200, {'Content-Type' => 'text/html'}, ['Not Found']]
31
+ end.any_number_of_times
32
+
33
+ env = Rack::MockRequest.env_for(path, {:method => :get})
34
+
35
+ subject.call(env)
36
+
37
+ called
38
+ end
39
+ end
40
+
41
+ def generate(args)
42
+ url_helpers.url_for(args.merge(:host => 'test.host'))
43
+ end
44
+
45
+ def url_helpers
46
+ subject.url_helpers
47
+ end
48
+
49
+
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: subdomainitis
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 9
8
+ - 0
9
+ version: 0.9.0
10
+ platform: ruby
11
+ authors:
12
+ - Stephen Judkins
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-21 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rails
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - "="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 3
43
+ - 0
44
+ - 1
45
+ version: 3.0.1
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: subdomainitis provides easy, simple support for using wildcard subdomains as controller parameters in Rails 3
49
+ email:
50
+ - stephen.judkins@gmail.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - lib/subdomainitis/spec_helpers.rb
59
+ - lib/subdomainitis.rb
60
+ - LICENSE
61
+ - README.md
62
+ has_rdoc: true
63
+ homepage: http://github.com/stephenjudkins/subdomainitis
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 1
86
+ - 3
87
+ - 6
88
+ version: 1.3.6
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.7
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Easy routing based on subdomains for Rails 3
96
+ test_files: []
97
+