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