apartment 0.23.0 → 0.23.1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -2
- data/Guardfile +24 -0
- data/HISTORY.md +5 -0
- data/README.md +20 -0
- data/apartment.gemspec +3 -3
- data/lib/apartment.rb +14 -11
- data/lib/apartment/adapters/abstract_adapter.rb +3 -3
- data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +4 -4
- data/lib/apartment/adapters/mysql2_adapter.rb +3 -2
- data/lib/apartment/adapters/postgresql_adapter.rb +12 -3
- data/lib/apartment/adapters/sqlite3_adapter.rb +2 -2
- data/lib/apartment/elevators/domain.rb +3 -3
- data/lib/apartment/elevators/first_subdomain.rb +2 -2
- data/lib/apartment/elevators/generic.rb +7 -2
- data/lib/apartment/elevators/host_hash.rb +1 -1
- data/lib/apartment/elevators/subdomain.rb +9 -9
- data/lib/apartment/migrator.rb +9 -4
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +8 -0
- data/lib/tasks/apartment.rake +6 -6
- data/spec/dummy/config/application.rb +0 -3
- data/spec/examples/schema_adapter_examples.rb +13 -0
- data/spec/unit/{middleware/domain_elevator_spec.rb → elevators/domain_spec.rb} +14 -7
- data/spec/unit/{middleware/first_subdomain_elevator_spec.rb → elevators/first_subdomain_spec.rb} +1 -1
- data/spec/unit/elevators/generic_spec.rb +37 -0
- data/spec/unit/elevators/host_hash_spec.rb +32 -0
- data/spec/unit/elevators/subdomain_spec.rb +36 -0
- data/spec/unit/migrator_spec.rb +23 -76
- data/spec/unit/reloader_spec.rb +1 -1
- metadata +20 -28
- data/circle.yml +0 -9
- data/spec/examples/elevator_examples.rb +0 -31
- data/spec/integration/middleware/domain_elevator_spec.rb +0 -10
- data/spec/integration/middleware/generic_elevator_spec.rb +0 -11
- data/spec/integration/middleware/subdomain_elevator_spec.rb +0 -35
- data/spec/unit/middleware/host_hash_elevator_spec.rb +0 -25
- data/spec/unit/middleware/subdomain_elevator_spec.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a231a3932b1b2bd5718861c0f70201d7502d4dd
|
4
|
+
data.tar.gz: 45ebf27d557562aaf6944b471fb5ea679f4b0d84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2b3e6efe7075333081133c60f96150ccb0227422545f669de98a8bf5db82bd971fa48a474448b3152238282c1201ec502bad5f16419fdbd4da985fa4aa30081
|
7
|
+
data.tar.gz: b6d1f23c13731c723c566af5f9e77ef4116d75b031b689f8333ee2773cf56c36806b8a7d023e2302372d9eba01c3e04bd23383edd662e0ae18e9b7958cd875f1
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -2,8 +2,14 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- 1.9.3
|
4
4
|
- 2.0.0
|
5
|
-
-
|
5
|
+
- 2.1.0
|
6
|
+
- jruby-19mode
|
6
7
|
gemfile:
|
7
8
|
- gemfiles/rails3.2.gemfile
|
8
9
|
- gemfiles/rails4.0.gemfile
|
9
|
-
bundler_args: --without local --verbose
|
10
|
+
bundler_args: --without local --verbose
|
11
|
+
before_install:
|
12
|
+
- gem install bundler -v '> 1.5.0'
|
13
|
+
env:
|
14
|
+
RUBY_GC_MALLOC_LIMIT: 90000000
|
15
|
+
RUBY_FREE_MIN: 200000
|
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/apartment/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
7
|
+
watch(%r{^lib/apartment/(.+)\.rb$}) { |m| "spec/integration/#{m[1]}_spec.rb" }
|
8
|
+
watch('spec/spec_helper.rb') { "spec" }
|
9
|
+
|
10
|
+
# # Rails example
|
11
|
+
# watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
12
|
+
# watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
13
|
+
# watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
14
|
+
# watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
15
|
+
# watch('config/routes.rb') { "spec/routing" }
|
16
|
+
# watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
17
|
+
|
18
|
+
# # Capybara features specs
|
19
|
+
# watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
20
|
+
|
21
|
+
# # Turnip features and steps
|
22
|
+
# watch(%r{^spec/acceptance/(.+)\.feature$})
|
23
|
+
# watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
24
|
+
end
|
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -19,6 +19,15 @@ Add the following to your Gemfile:
|
|
19
19
|
gem 'apartment'
|
20
20
|
```
|
21
21
|
|
22
|
+
Then generate your `Apartment` config file using
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
bundle exec rails generate apartment:install
|
26
|
+
```
|
27
|
+
|
28
|
+
This will create a `config/initializers/apartment.rb` initializer file.
|
29
|
+
Configure as needed using the docs below.
|
30
|
+
|
22
31
|
That's all you need to set up the Apartment libraries. If you want to switch databases
|
23
32
|
on a per-user basis, look under "Usage - Switching databases per request", below.
|
24
33
|
|
@@ -70,6 +79,17 @@ database, call switch with no arguments.
|
|
70
79
|
You can have Apartment route to the appropriate database by adding some Rack middleware.
|
71
80
|
Apartment can support many different "Elevators" that can take care of this routing to your data.
|
72
81
|
|
82
|
+
The initializer above will generate the appropriate code for the Subdomain elevator
|
83
|
+
by default. You can see this in `config/initializers/apartment.rb` after running
|
84
|
+
that generator. If you're *not* using the generator, you can specify your
|
85
|
+
elevator below. Note that in this case you will **need** to require the elevator
|
86
|
+
manually in your `application.rb` like so
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
# config/application.rb
|
90
|
+
require 'apartment/elevators/subdomain' # or 'domain' or 'generic'
|
91
|
+
```
|
92
|
+
|
73
93
|
**Switch on subdomain**
|
74
94
|
In house, we use the subdomain elevator, which analyzes the subdomain of the request and switches to a database schema of the same name. It can be used like so:
|
75
95
|
|
data/apartment.gemspec
CHANGED
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
s.add_development_dependency 'appraisal'
|
25
25
|
s.add_development_dependency 'rake', '~> 0.9'
|
26
|
-
s.add_development_dependency 'rspec',
|
27
|
-
s.add_development_dependency 'rspec
|
26
|
+
s.add_development_dependency 'rspec-rails', '~> 2.14'
|
27
|
+
s.add_development_dependency 'guard-rspec', '~> 4.2'
|
28
28
|
s.add_development_dependency 'capybara', '~> 1.0.0'
|
29
29
|
|
30
30
|
if defined?(JRUBY_VERSION)
|
@@ -39,4 +39,4 @@ Gem::Specification.new do |s|
|
|
39
39
|
s.add_development_dependency 'pg', '>= 0.11.0'
|
40
40
|
s.add_development_dependency 'sqlite3'
|
41
41
|
end
|
42
|
-
end
|
42
|
+
end
|
data/lib/apartment.rb
CHANGED
@@ -68,23 +68,26 @@ module Apartment
|
|
68
68
|
end
|
69
69
|
|
70
70
|
# Exceptions
|
71
|
-
|
71
|
+
ApartmentError = Class.new(StandardError)
|
72
72
|
|
73
73
|
# Raised when apartment cannot find the adapter specified in <tt>config/database.yml</tt>
|
74
|
-
|
74
|
+
AdapterNotFound = Class.new(ApartmentError)
|
75
75
|
|
76
|
-
#
|
77
|
-
|
76
|
+
# Tenant specified is unknown
|
77
|
+
TenantNotFound = Class.new(ApartmentError)
|
78
78
|
|
79
|
-
# Raised when
|
80
|
-
|
79
|
+
# Raised when database cannot find the specified database
|
80
|
+
DatabaseNotFound = Class.new(TenantNotFound)
|
81
81
|
|
82
82
|
# Raised when database cannot find the specified schema
|
83
|
-
|
83
|
+
SchemaNotFound = Class.new(TenantNotFound)
|
84
84
|
|
85
|
-
#
|
86
|
-
|
85
|
+
# The Tenant attempting to be created already exists
|
86
|
+
TenantExists = Class.new(ApartmentError)
|
87
87
|
|
88
|
-
# Raised when
|
89
|
-
|
88
|
+
# Raised when trying to create a database that already exists
|
89
|
+
DatabaseExists = Class.new(TenantExists)
|
90
|
+
|
91
|
+
# Raised when trying to create a schema that already exists
|
92
|
+
SchemaExists = Class.new(TenantExists)
|
90
93
|
end
|
@@ -14,7 +14,7 @@ module Apartment
|
|
14
14
|
# @param {String} database Database name
|
15
15
|
#
|
16
16
|
def create(database)
|
17
|
-
|
17
|
+
create_tenant(database)
|
18
18
|
|
19
19
|
process(database) do
|
20
20
|
import_database_schema
|
@@ -106,7 +106,7 @@ module Apartment
|
|
106
106
|
#
|
107
107
|
# @param {String} database Database name
|
108
108
|
#
|
109
|
-
def
|
109
|
+
def create_tenant(database)
|
110
110
|
Apartment.connection.create_database( environmentify(database) )
|
111
111
|
|
112
112
|
rescue *rescuable_exceptions
|
@@ -183,4 +183,4 @@ module Apartment
|
|
183
183
|
end
|
184
184
|
end
|
185
185
|
end
|
186
|
-
end
|
186
|
+
end
|
@@ -5,8 +5,8 @@ module Apartment
|
|
5
5
|
|
6
6
|
def self.jdbc_postgresql_adapter(config)
|
7
7
|
Apartment.use_schemas ?
|
8
|
-
|
9
|
-
|
8
|
+
Adapters::JDBCPostgresqlSchemaAdapter.new(config) :
|
9
|
+
Adapters::JDBCPostgresqlAdapter.new(config)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -17,7 +17,7 @@ module Apartment
|
|
17
17
|
|
18
18
|
protected
|
19
19
|
|
20
|
-
def
|
20
|
+
def create_tenant(database)
|
21
21
|
# There is a bug in activerecord-jdbcpostgresql-adapter (1.2.5) that will cause
|
22
22
|
# an exception if no options are passed into the create_database call.
|
23
23
|
Apartment.connection.create_database(environmentify(database), { :thisisahack => '' })
|
@@ -64,4 +64,4 @@ module Apartment
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
67
|
-
end
|
67
|
+
end
|
@@ -24,6 +24,12 @@ module Apartment
|
|
24
24
|
# Separate Adapter for Postgresql when using schemas
|
25
25
|
class PostgresqlSchemaAdapter < AbstractAdapter
|
26
26
|
|
27
|
+
def initialize(config)
|
28
|
+
super
|
29
|
+
|
30
|
+
reset
|
31
|
+
end
|
32
|
+
|
27
33
|
# Drop the database schema
|
28
34
|
#
|
29
35
|
# @param {String} database Database (schema) to drop
|
@@ -83,7 +89,7 @@ module Apartment
|
|
83
89
|
|
84
90
|
# Create the new schema
|
85
91
|
#
|
86
|
-
def
|
92
|
+
def create_tenant(database)
|
87
93
|
Apartment.connection.execute(%{CREATE SCHEMA "#{database}"})
|
88
94
|
|
89
95
|
rescue *rescuable_exceptions
|
@@ -95,8 +101,11 @@ module Apartment
|
|
95
101
|
# Generate the final search path to set including persistent_schemas
|
96
102
|
#
|
97
103
|
def full_search_path
|
98
|
-
persistent_schemas
|
99
|
-
|
104
|
+
persistent_schemas.map(&:inspect).join(", ")
|
105
|
+
end
|
106
|
+
|
107
|
+
def persistent_schemas
|
108
|
+
[@current_database, Apartment.persistent_schemas].flatten
|
100
109
|
end
|
101
110
|
end
|
102
111
|
end
|
@@ -26,7 +26,7 @@ module Apartment
|
|
26
26
|
File.basename(Apartment.connection.instance_variable_get(:@config)[:database], '.sqlite3')
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
protected
|
30
30
|
|
31
31
|
def connect_to_new(database)
|
32
32
|
raise DatabaseNotFound,
|
@@ -35,7 +35,7 @@ module Apartment
|
|
35
35
|
super database_file(database)
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def create_tenant(database)
|
39
39
|
raise DatabaseExists,
|
40
40
|
"The database #{environmentify(database)} already exists." if File.exists?(database_file(database))
|
41
41
|
|
@@ -2,15 +2,15 @@ require 'apartment/elevators/generic'
|
|
2
2
|
|
3
3
|
module Apartment
|
4
4
|
module Elevators
|
5
|
-
# Provides a rack based
|
6
|
-
# Assumes that
|
5
|
+
# Provides a rack based tenant switching solution based on domain
|
6
|
+
# Assumes that tenant name should match domain
|
7
7
|
# Parses request host for second level domain
|
8
8
|
# eg. example.com => example
|
9
9
|
# www.example.bc.ca => example
|
10
10
|
#
|
11
11
|
class Domain < Generic
|
12
12
|
|
13
|
-
def
|
13
|
+
def parse_tenant_name(request)
|
14
14
|
return nil if request.host.blank?
|
15
15
|
|
16
16
|
request.host.match(/(www\.)?(?<sld>[^.]*)/)["sld"]
|
@@ -2,14 +2,14 @@ require 'apartment/elevators/subdomain'
|
|
2
2
|
|
3
3
|
module Apartment
|
4
4
|
module Elevators
|
5
|
-
# Provides a rack based
|
5
|
+
# Provides a rack based tenant switching solution based on the first subdomain
|
6
6
|
# of a given domain name.
|
7
7
|
# eg:
|
8
8
|
# - example1.domain.com => example1
|
9
9
|
# - example2.something.domain.com => example2
|
10
10
|
class FirstSubdomain < Subdomain
|
11
11
|
|
12
|
-
def
|
12
|
+
def parse_tenant_name(request)
|
13
13
|
super.split('.')[0]
|
14
14
|
end
|
15
15
|
end
|
@@ -3,13 +3,13 @@ require 'apartment/database'
|
|
3
3
|
|
4
4
|
module Apartment
|
5
5
|
module Elevators
|
6
|
-
# Provides a rack based
|
6
|
+
# Provides a rack based tenant switching solution based on request
|
7
7
|
#
|
8
8
|
class Generic
|
9
9
|
|
10
10
|
def initialize(app, processor = nil)
|
11
11
|
@app = app
|
12
|
-
@processor = processor || method(:
|
12
|
+
@processor = processor || method(:parse_tenant_name)
|
13
13
|
end
|
14
14
|
|
15
15
|
def call(env)
|
@@ -23,6 +23,11 @@ module Apartment
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def parse_database_name(request)
|
26
|
+
warn "[DEPRECATED] - Use #parse_tenant_name"
|
27
|
+
parse_tenant_name(request)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_tenant_name(request)
|
26
31
|
raise "Override"
|
27
32
|
end
|
28
33
|
end
|
@@ -2,33 +2,33 @@ require 'apartment/elevators/generic'
|
|
2
2
|
|
3
3
|
module Apartment
|
4
4
|
module Elevators
|
5
|
-
# Provides a rack based
|
6
|
-
# Assumes that
|
5
|
+
# Provides a rack based tenant switching solution based on subdomains
|
6
|
+
# Assumes that tenant name should match subdomain
|
7
7
|
#
|
8
8
|
class Subdomain < Generic
|
9
9
|
def self.excluded_subdomains
|
10
|
-
|
10
|
+
@excluded_subdomains ||= []
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.excluded_subdomains=(arg)
|
14
|
-
|
14
|
+
@excluded_subdomains = arg
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def parse_tenant_name(request)
|
18
18
|
request_subdomain = subdomain(request.host)
|
19
19
|
|
20
|
-
# If the domain acquired is set to be
|
20
|
+
# If the domain acquired is set to be excluded, set the tenant to whatever is currently
|
21
21
|
# next in line in the schema search path.
|
22
|
-
|
22
|
+
tenant = if self.class.excluded_subdomains.include?(request_subdomain)
|
23
23
|
nil
|
24
24
|
else
|
25
25
|
request_subdomain
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
tenant.presence
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
protected
|
32
32
|
|
33
33
|
# *Almost* a direct ripoff of ActionDispatch::Request subdomain methods
|
34
34
|
|
data/lib/apartment/migrator.rb
CHANGED
@@ -8,7 +8,9 @@ module Apartment
|
|
8
8
|
# Migrate to latest
|
9
9
|
def migrate(database)
|
10
10
|
Database.process(database) do
|
11
|
-
|
11
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
12
|
+
|
13
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_path, version) do |migration|
|
12
14
|
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
13
15
|
end
|
14
16
|
end
|
@@ -16,13 +18,16 @@ module Apartment
|
|
16
18
|
|
17
19
|
# Migrate up/down to a specific version
|
18
20
|
def run(direction, database, version)
|
19
|
-
Database.process(database)
|
21
|
+
Database.process(database) do
|
22
|
+
ActiveRecord::Migrator.run(direction, ActiveRecord::Migrator.migrations_path, version)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
# rollback latest migration `step` number of times
|
23
27
|
def rollback(database, step = 1)
|
24
|
-
Database.process(database)
|
28
|
+
Database.process(database) do
|
29
|
+
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_path, step)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
|
-
|
28
33
|
end
|
data/lib/apartment/version.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# Require whichever elevator you're using below here...
|
2
|
+
#
|
3
|
+
# require 'apartment/elevators/generic'
|
4
|
+
# require 'apartment/elevators/domain'
|
5
|
+
require 'apartment/elevators/subdomain'
|
6
|
+
|
1
7
|
#
|
2
8
|
# Apartment Configuration
|
3
9
|
#
|
@@ -5,6 +11,8 @@ Apartment.configure do |config|
|
|
5
11
|
|
6
12
|
# these models will not be multi-tenanted,
|
7
13
|
# but remain in the global (public) namespace
|
14
|
+
# Note that ActiveRecord::SessionStore::Session is just an example
|
15
|
+
# you may not even use the AR Session Store, in which case you'd remove that line
|
8
16
|
config.excluded_models = %w{
|
9
17
|
ActiveRecord::SessionStore::Session
|
10
18
|
}
|
data/lib/tasks/apartment.rake
CHANGED
@@ -8,7 +8,7 @@ apartment_namespace = namespace :apartment do
|
|
8
8
|
begin
|
9
9
|
puts("Creating #{db} database")
|
10
10
|
quietly { Apartment::Database.create(db) }
|
11
|
-
rescue Apartment::
|
11
|
+
rescue Apartment::TenantExists => e
|
12
12
|
puts e.message
|
13
13
|
end
|
14
14
|
end
|
@@ -21,7 +21,7 @@ apartment_namespace = namespace :apartment do
|
|
21
21
|
begin
|
22
22
|
puts("Migrating #{db} database")
|
23
23
|
Apartment::Migrator.migrate db
|
24
|
-
rescue Apartment::
|
24
|
+
rescue Apartment::TenantNotFound => e
|
25
25
|
puts e.message
|
26
26
|
end
|
27
27
|
end
|
@@ -36,7 +36,7 @@ apartment_namespace = namespace :apartment do
|
|
36
36
|
Apartment::Database.process(db) do
|
37
37
|
Apartment::Database.seed
|
38
38
|
end
|
39
|
-
rescue Apartment::
|
39
|
+
rescue Apartment::TenantNotFound => e
|
40
40
|
puts e.message
|
41
41
|
end
|
42
42
|
end
|
@@ -50,7 +50,7 @@ apartment_namespace = namespace :apartment do
|
|
50
50
|
begin
|
51
51
|
puts("Rolling back #{db} database")
|
52
52
|
Apartment::Migrator.rollback db, step
|
53
|
-
rescue Apartment::
|
53
|
+
rescue Apartment::TenantNotFound => e
|
54
54
|
puts e.message
|
55
55
|
end
|
56
56
|
end
|
@@ -67,7 +67,7 @@ apartment_namespace = namespace :apartment do
|
|
67
67
|
begin
|
68
68
|
puts("Migrating #{db} database up")
|
69
69
|
Apartment::Migrator.run :up, db, version
|
70
|
-
rescue Apartment::
|
70
|
+
rescue Apartment::TenantNotFound => e
|
71
71
|
puts e.message
|
72
72
|
end
|
73
73
|
end
|
@@ -82,7 +82,7 @@ apartment_namespace = namespace :apartment do
|
|
82
82
|
begin
|
83
83
|
puts("Migrating #{db} database down")
|
84
84
|
Apartment::Migrator.run :down, db, version
|
85
|
-
rescue Apartment::
|
85
|
+
rescue Apartment::TenantNotFound => e
|
86
86
|
puts e.message
|
87
87
|
end
|
88
88
|
end
|
@@ -18,9 +18,6 @@ module Dummy
|
|
18
18
|
require 'apartment/elevators/domain'
|
19
19
|
|
20
20
|
config.middleware.use 'Apartment::Elevators::Subdomain'
|
21
|
-
config.middleware.use 'Apartment::Elevators::Domain'
|
22
|
-
# Our test for this middleware is using a query_string couldn't think of a better way to differentiate it from the other middleware
|
23
|
-
config.middleware.use 'Apartment::Elevators::Generic', Proc.new { |request| request.query_string.split('=').last if request.query_string.present? }
|
24
21
|
|
25
22
|
# Custom directories with classes and modules you want to be autoloadable.
|
26
23
|
config.autoload_paths += %W(#{config.root}/lib)
|
@@ -28,6 +28,19 @@ shared_examples_for "a schema based apartment adapter" do
|
|
28
28
|
|
29
29
|
Company.table_name.should == "#{default_schema}.companies"
|
30
30
|
end
|
31
|
+
|
32
|
+
it 'sets the search_path correctly' do
|
33
|
+
Apartment::Database.init
|
34
|
+
|
35
|
+
User.connection.schema_search_path.should =~ %r|#{default_schema}|
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "persistent_schemas", :persistent_schemas => true do
|
40
|
+
it "sets the persistent schemas in the schema_search_path" do
|
41
|
+
Apartment::Database.init
|
42
|
+
connection.schema_search_path.should end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
|
43
|
+
end
|
31
44
|
end
|
32
45
|
end
|
33
46
|
|
@@ -3,23 +3,30 @@ require 'apartment/elevators/domain'
|
|
3
3
|
|
4
4
|
describe Apartment::Elevators::Domain do
|
5
5
|
|
6
|
-
|
6
|
+
subject(:elevator){ described_class.new(Proc.new{}) }
|
7
|
+
|
8
|
+
describe "#parse_tenant_name" do
|
7
9
|
it "parses the host for a domain name" do
|
8
10
|
request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
|
9
|
-
elevator
|
10
|
-
elevator.parse_database_name(request).should == 'example'
|
11
|
+
elevator.parse_tenant_name(request).should == 'example'
|
11
12
|
end
|
12
13
|
|
13
14
|
it "ignores a www prefix and domain suffix" do
|
14
15
|
request = ActionDispatch::Request.new('HTTP_HOST' => 'www.example.bc.ca')
|
15
|
-
elevator
|
16
|
-
elevator.parse_database_name(request).should == 'example'
|
16
|
+
elevator.parse_tenant_name(request).should == 'example'
|
17
17
|
end
|
18
18
|
|
19
19
|
it "returns nil if there is no host" do
|
20
20
|
request = ActionDispatch::Request.new('HTTP_HOST' => '')
|
21
|
-
elevator
|
22
|
-
|
21
|
+
elevator.parse_tenant_name(request).should be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#call" do
|
26
|
+
it "switches to the proper tenant" do
|
27
|
+
Apartment::Database.should_receive(:switch).with('example')
|
28
|
+
|
29
|
+
elevator.call('HTTP_HOST' => 'www.example.com')
|
23
30
|
end
|
24
31
|
end
|
25
32
|
end
|
data/spec/unit/{middleware/first_subdomain_elevator_spec.rb → elevators/first_subdomain_spec.rb}
RENAMED
@@ -3,7 +3,7 @@ require 'apartment/elevators/first_subdomain'
|
|
3
3
|
|
4
4
|
describe Apartment::Elevators::FirstSubdomain do
|
5
5
|
describe "subdomain" do
|
6
|
-
subject { described_class.new("test").
|
6
|
+
subject { described_class.new("test").parse_tenant_name(request) }
|
7
7
|
let(:request) { double(:request, :host => "#{subdomain}.example.com") }
|
8
8
|
|
9
9
|
context "one subdomain" do
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apartment/elevators/generic'
|
3
|
+
|
4
|
+
describe Apartment::Elevators::Generic do
|
5
|
+
|
6
|
+
class MyElevator < described_class
|
7
|
+
def parse_tenant_name(*)
|
8
|
+
'tenant2'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject(:elevator){ described_class.new(Proc.new{}) }
|
13
|
+
|
14
|
+
describe "#call" do
|
15
|
+
it "calls the processor if given" do
|
16
|
+
elevator = described_class.new(Proc.new{}, Proc.new{'tenant1'})
|
17
|
+
|
18
|
+
Apartment::Database.should_receive(:switch).with('tenant1')
|
19
|
+
|
20
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises if parse_tenant_name not implemented" do
|
24
|
+
expect {
|
25
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
26
|
+
}.to raise_error(RuntimeError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "switches to the parsed db_name" do
|
30
|
+
elevator = MyElevator.new(Proc.new{})
|
31
|
+
|
32
|
+
Apartment::Database.should_receive(:switch).with('tenant2')
|
33
|
+
|
34
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apartment/elevators/host_hash'
|
3
|
+
|
4
|
+
describe Apartment::Elevators::HostHash do
|
5
|
+
|
6
|
+
subject(:elevator){ Apartment::Elevators::HostHash.new(Proc.new{}, 'example.com' => 'example_tenant') }
|
7
|
+
|
8
|
+
describe "#parse_tenant_name" do
|
9
|
+
it "parses the host for a domain name" do
|
10
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
|
11
|
+
elevator.parse_tenant_name(request).should == 'example_tenant'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "raises DatabaseNotFound exception if there is no host" do
|
15
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => '')
|
16
|
+
expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::DatabaseNotFound)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "raises DatabaseNotFound exception if there is no database associated to current host" do
|
20
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
|
21
|
+
expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::DatabaseNotFound)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#call" do
|
26
|
+
it "switches to the proper tenant" do
|
27
|
+
Apartment::Database.should_receive(:switch).with('example_tenant')
|
28
|
+
|
29
|
+
elevator.call('HTTP_HOST' => 'example.com')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apartment/elevators/subdomain'
|
3
|
+
|
4
|
+
describe Apartment::Elevators::Subdomain do
|
5
|
+
|
6
|
+
subject(:elevator){ described_class.new(Proc.new{}) }
|
7
|
+
|
8
|
+
describe "#parse_tenant_name" do
|
9
|
+
it "should parse subdomain" do
|
10
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
|
11
|
+
elevator.parse_tenant_name(request).should == 'foo'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return nil when no subdomain" do
|
15
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com')
|
16
|
+
elevator.parse_tenant_name(request).should be_nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#call" do
|
21
|
+
it "switches to the proper tenant" do
|
22
|
+
Apartment::Database.should_receive(:switch).with('tenant1')
|
23
|
+
elevator.call('HTTP_HOST' => 'tenant1.example.com')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "ignores excluded subdomains" do
|
27
|
+
described_class.excluded_subdomains = %w{foo}
|
28
|
+
|
29
|
+
Apartment::Database.should_not_receive(:switch)
|
30
|
+
|
31
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
32
|
+
|
33
|
+
described_class.excluded_subdomains = nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/unit/migrator_spec.rb
CHANGED
@@ -1,90 +1,37 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'apartment/migrator'
|
3
3
|
|
4
|
-
describe Apartment::Migrator
|
4
|
+
describe Apartment::Migrator do
|
5
5
|
|
6
|
-
let(:
|
7
|
-
let(:version){ 20110613152810 } # note this is brittle! I've literally just taken the version of the one migration I made... don't change this version
|
6
|
+
let(:tenant){ Apartment::Test.next_db }
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
Apartment::Database.stub(:config).and_return config # Use postgresql config for this test
|
12
|
-
@original_schema = ActiveRecord::Base.connection.schema_search_path
|
13
|
-
# Necessary because the JDBC adapter returns $user in the search path
|
14
|
-
@original_schema.gsub!(/"\$user",/, '') if defined?(JRUBY_VERSION)
|
8
|
+
# Don't need a real switch here, just testing behaviour
|
9
|
+
before { Apartment::Database.adapter.stub(:connect_to_new) }
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
Apartment::Database.create schema_name # create the schema
|
23
|
-
migrations_path = Rails.root + ActiveRecord::Migrator.migrations_path # tell AR where the real migrations are
|
24
|
-
ActiveRecord::Migrator.stub(:migrations_path).and_return(migrations_path)
|
25
|
-
end
|
11
|
+
describe "::migrate" do
|
12
|
+
it "processes and migrates" do
|
13
|
+
expect(Apartment::Database).to receive(:process).with(tenant).and_call_original
|
14
|
+
expect(ActiveRecord::Migrator).to receive(:migrate)
|
26
15
|
|
27
|
-
|
28
|
-
|
16
|
+
Apartment::Migrator.migrate(tenant)
|
17
|
+
end
|
29
18
|
end
|
30
19
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
context "using schemas" do
|
36
|
-
|
37
|
-
describe "#migrate" do
|
38
|
-
it "should connect to new db, then reset when done" do
|
39
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
|
40
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
|
41
|
-
Apartment::Migrator.migrate(schema_name)
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should migrate db" do
|
45
|
-
ActiveRecord::Migrator.should_receive(:migrate)
|
46
|
-
Apartment::Migrator.migrate(schema_name)
|
47
|
-
end
|
48
|
-
end
|
20
|
+
describe "::run" do
|
21
|
+
it "processes and runs" do
|
22
|
+
expect(Apartment::Database).to receive(:process).with(tenant).and_call_original
|
23
|
+
expect(ActiveRecord::Migrator).to receive(:run).with(:up, anything, 1234)
|
49
24
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
it "should connect to new db, then reset when done" do
|
54
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
|
55
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
|
56
|
-
Apartment::Migrator.run(:up, schema_name, version)
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should migrate to a version" do
|
60
|
-
ActiveRecord::Migrator.should_receive(:run).with(:up, anything, version)
|
61
|
-
Apartment::Migrator.run(:up, schema_name, version)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "down" do
|
66
|
-
|
67
|
-
it "should connect to new db, then reset when done" do
|
68
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
|
69
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
|
70
|
-
Apartment::Migrator.run(:down, schema_name, version)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should migrate to a version" do
|
74
|
-
ActiveRecord::Migrator.should_receive(:run).with(:down, anything, version)
|
75
|
-
Apartment::Migrator.run(:down, schema_name, version)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
25
|
+
Apartment::Migrator.run(:up, tenant, 1234)
|
26
|
+
end
|
27
|
+
end
|
79
28
|
|
80
|
-
|
81
|
-
|
29
|
+
describe "::rollback" do
|
30
|
+
it "processes and rolls back" do
|
31
|
+
expect(Apartment::Database).to receive(:process).with(tenant).and_call_original
|
32
|
+
expect(ActiveRecord::Migrator).to receive(:rollback).with(anything, 2)
|
82
33
|
|
83
|
-
|
84
|
-
ActiveRecord::Migrator.should_receive(:rollback).with(anything, steps)
|
85
|
-
Apartment::Migrator.rollback(schema_name, steps)
|
86
|
-
end
|
87
|
-
end
|
34
|
+
Apartment::Migrator.rollback(tenant, 2)
|
88
35
|
end
|
89
36
|
end
|
90
|
-
end
|
37
|
+
end
|
data/spec/unit/reloader_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe Apartment::Reloader do
|
|
13
13
|
Company.reset_table_name # ensure we're clean
|
14
14
|
end
|
15
15
|
|
16
|
-
subject{ Apartment::Reloader.new(
|
16
|
+
subject{ Apartment::Reloader.new(double("Rack::Application", :call => nil)) }
|
17
17
|
|
18
18
|
it "should initialize apartment when called" do
|
19
19
|
Company.table_name.should_not include('public.')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apartment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.23.
|
4
|
+
version: 0.23.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Brunner
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -68,33 +68,33 @@ dependencies:
|
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0.9'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
|
-
name: rspec
|
71
|
+
name: rspec-rails
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: '2.
|
76
|
+
version: '2.14'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - ~>
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '2.
|
83
|
+
version: '2.14'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
|
-
name: rspec
|
85
|
+
name: guard-rspec
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
88
|
- - ~>
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version: '2
|
90
|
+
version: '4.2'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
95
|
- - ~>
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
version: '2
|
97
|
+
version: '4.2'
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: capybara
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,16 +168,14 @@ files:
|
|
168
168
|
- .travis.yml
|
169
169
|
- Appraisals
|
170
170
|
- Gemfile
|
171
|
+
- Guardfile
|
171
172
|
- HISTORY.md
|
172
173
|
- README.md
|
173
174
|
- Rakefile
|
174
175
|
- TODO.md
|
175
176
|
- apartment.gemspec
|
176
|
-
- circle.yml
|
177
177
|
- gemfiles/rails3.2.gemfile
|
178
|
-
- gemfiles/rails3.2.gemfile.lock
|
179
178
|
- gemfiles/rails4.0.gemfile
|
180
|
-
- gemfiles/rails4.0.gemfile.lock
|
181
179
|
- lib/apartment.rb
|
182
180
|
- lib/apartment/adapters/abstract_adapter.rb
|
183
181
|
- lib/apartment/adapters/abstract_jdbc_adapter.rb
|
@@ -245,13 +243,9 @@ files:
|
|
245
243
|
- spec/dummy/public/stylesheets/.gitkeep
|
246
244
|
- spec/dummy/script/rails
|
247
245
|
- spec/examples/connection_adapter_examples.rb
|
248
|
-
- spec/examples/elevator_examples.rb
|
249
246
|
- spec/examples/generic_adapter_examples.rb
|
250
247
|
- spec/examples/schema_adapter_examples.rb
|
251
248
|
- spec/integration/apartment_rake_integration_spec.rb
|
252
|
-
- spec/integration/middleware/domain_elevator_spec.rb
|
253
|
-
- spec/integration/middleware/generic_elevator_spec.rb
|
254
|
-
- spec/integration/middleware/subdomain_elevator_spec.rb
|
255
249
|
- spec/integration/query_caching_spec.rb
|
256
250
|
- spec/schemas/v1.rb
|
257
251
|
- spec/schemas/v2.rb
|
@@ -265,10 +259,11 @@ files:
|
|
265
259
|
- spec/support/setup.rb
|
266
260
|
- spec/tasks/apartment_rake_spec.rb
|
267
261
|
- spec/unit/config_spec.rb
|
268
|
-
- spec/unit/
|
269
|
-
- spec/unit/
|
270
|
-
- spec/unit/
|
271
|
-
- spec/unit/
|
262
|
+
- spec/unit/elevators/domain_spec.rb
|
263
|
+
- spec/unit/elevators/first_subdomain_spec.rb
|
264
|
+
- spec/unit/elevators/generic_spec.rb
|
265
|
+
- spec/unit/elevators/host_hash_spec.rb
|
266
|
+
- spec/unit/elevators/subdomain_spec.rb
|
272
267
|
- spec/unit/migrator_spec.rb
|
273
268
|
- spec/unit/reloader_spec.rb
|
274
269
|
homepage: https://github.com/influitive/apartment
|
@@ -291,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
291
286
|
version: '0'
|
292
287
|
requirements: []
|
293
288
|
rubyforge_project:
|
294
|
-
rubygems_version: 2.1.
|
289
|
+
rubygems_version: 2.1.11
|
295
290
|
signing_key:
|
296
291
|
specification_version: 4
|
297
292
|
summary: A Ruby gem for managing database multitenancy
|
@@ -339,13 +334,9 @@ test_files:
|
|
339
334
|
- spec/dummy/public/stylesheets/.gitkeep
|
340
335
|
- spec/dummy/script/rails
|
341
336
|
- spec/examples/connection_adapter_examples.rb
|
342
|
-
- spec/examples/elevator_examples.rb
|
343
337
|
- spec/examples/generic_adapter_examples.rb
|
344
338
|
- spec/examples/schema_adapter_examples.rb
|
345
339
|
- spec/integration/apartment_rake_integration_spec.rb
|
346
|
-
- spec/integration/middleware/domain_elevator_spec.rb
|
347
|
-
- spec/integration/middleware/generic_elevator_spec.rb
|
348
|
-
- spec/integration/middleware/subdomain_elevator_spec.rb
|
349
340
|
- spec/integration/query_caching_spec.rb
|
350
341
|
- spec/schemas/v1.rb
|
351
342
|
- spec/schemas/v2.rb
|
@@ -359,9 +350,10 @@ test_files:
|
|
359
350
|
- spec/support/setup.rb
|
360
351
|
- spec/tasks/apartment_rake_spec.rb
|
361
352
|
- spec/unit/config_spec.rb
|
362
|
-
- spec/unit/
|
363
|
-
- spec/unit/
|
364
|
-
- spec/unit/
|
365
|
-
- spec/unit/
|
353
|
+
- spec/unit/elevators/domain_spec.rb
|
354
|
+
- spec/unit/elevators/first_subdomain_spec.rb
|
355
|
+
- spec/unit/elevators/generic_spec.rb
|
356
|
+
- spec/unit/elevators/host_hash_spec.rb
|
357
|
+
- spec/unit/elevators/subdomain_spec.rb
|
366
358
|
- spec/unit/migrator_spec.rb
|
367
359
|
- spec/unit/reloader_spec.rb
|
data/circle.yml
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
shared_examples_for "an apartment elevator" do
|
4
|
-
|
5
|
-
context "single request" do
|
6
|
-
it "should switch the db" do
|
7
|
-
ActiveRecord::Base.connection.schema_search_path.should_not == %{"#{db1}"}
|
8
|
-
|
9
|
-
visit(domain1)
|
10
|
-
ActiveRecord::Base.connection.schema_search_path.should == %{"#{db1}"}
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context "simultaneous requests" do
|
15
|
-
|
16
|
-
let!(:c1_user_count) { api.process(db1){ (2 + rand(2)).times{ User.create } } }
|
17
|
-
let!(:c2_user_count) { api.process(db2){ (c1_user_count + 2).times{ User.create } } }
|
18
|
-
|
19
|
-
it "should fetch the correct user count for each session based on the elevator processor" do
|
20
|
-
visit(domain1)
|
21
|
-
|
22
|
-
in_new_session do |session|
|
23
|
-
session.visit(domain2)
|
24
|
-
User.count.should == c2_user_count
|
25
|
-
end
|
26
|
-
|
27
|
-
visit(domain1)
|
28
|
-
User.count.should == c1_user_count
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'apartment/elevators/generic'
|
3
|
-
|
4
|
-
describe Apartment::Elevators::Generic, elevator: true do
|
5
|
-
|
6
|
-
# NOTE, see spec/dummy/config/application.rb to see the Proc that defines the behaviour here
|
7
|
-
let(:domain1) { "http://#{db1}.com?db=#{db1}" }
|
8
|
-
let(:domain2) { "http://#{db2}.com?db=#{db2}" }
|
9
|
-
|
10
|
-
it_should_behave_like "an apartment elevator"
|
11
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'apartment/elevators/generic'
|
3
|
-
|
4
|
-
describe Apartment::Elevators::Subdomain, elevator: true do
|
5
|
-
|
6
|
-
let(:domain1) { "http://#{db1}.example.com" }
|
7
|
-
let(:domain2) { "http://#{db2}.example.com" }
|
8
|
-
|
9
|
-
it_should_behave_like "an apartment elevator"
|
10
|
-
|
11
|
-
context "With Subdomain Excluded" do
|
12
|
-
let(:domain_with_excluded_subdomain) { "http://www.example.com" }
|
13
|
-
|
14
|
-
before do
|
15
|
-
Apartment::Elevators::Subdomain.excluded_subdomains = %w(www)
|
16
|
-
# FIXME:
|
17
|
-
# This is used because the dummy app includes all three middlewares. The domain middleware specifically
|
18
|
-
# tries to lookup the example schema and tries to switch to it. I don't know how to go around this.
|
19
|
-
Apartment::Database.create("example")
|
20
|
-
end
|
21
|
-
|
22
|
-
it_should_behave_like "an apartment elevator"
|
23
|
-
|
24
|
-
it "shouldnt switch the schema if the subdomain is excluded" do
|
25
|
-
ActiveRecord::Base.connection.schema_search_path.scan(/\w+/).should_not include("www")
|
26
|
-
visit(domain_with_excluded_subdomain)
|
27
|
-
ActiveRecord::Base.connection.schema_search_path.scan(/\w+/).should_not include("www")
|
28
|
-
end
|
29
|
-
|
30
|
-
after do
|
31
|
-
Apartment::Elevators::Subdomain.excluded_subdomains = []
|
32
|
-
Apartment::Database.drop("example")
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'apartment/elevators/host_hash'
|
3
|
-
|
4
|
-
describe Apartment::Elevators::HostHash do
|
5
|
-
|
6
|
-
describe "#parse_database_name" do
|
7
|
-
it "parses the host for a domain name" do
|
8
|
-
request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
|
9
|
-
elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
|
10
|
-
elevator.parse_database_name(request).should == 'example_database'
|
11
|
-
end
|
12
|
-
|
13
|
-
it "raises DatabaseNotFound exception if there is no host" do
|
14
|
-
request = ActionDispatch::Request.new('HTTP_HOST' => '')
|
15
|
-
elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
|
16
|
-
expect { elevator.parse_database_name(request) }.to raise_error(Apartment::DatabaseNotFound)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "raises DatabaseNotFound exception if there is no database associated to current host" do
|
20
|
-
request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
|
21
|
-
elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
|
22
|
-
expect { elevator.parse_database_name(request) }.to raise_error(Apartment::DatabaseNotFound)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'apartment/elevators/subdomain'
|
3
|
-
|
4
|
-
describe Apartment::Elevators::Subdomain do
|
5
|
-
|
6
|
-
describe "#parse_database_name" do
|
7
|
-
it "should parse subdomain" do
|
8
|
-
request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
|
9
|
-
elevator = Apartment::Elevators::Subdomain.new(nil)
|
10
|
-
elevator.parse_database_name(request).should == 'foo'
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should return nil when no subdomain" do
|
14
|
-
request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com')
|
15
|
-
elevator = Apartment::Elevators::Subdomain.new(nil)
|
16
|
-
elevator.parse_database_name(request).should be_nil
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|