apartment 2.0.0 → 2.1.0
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/.github/ISSUE_TEMPLATE.md +21 -0
- data/.travis.yml +4 -7
- data/HISTORY.md +5 -0
- data/README.md +57 -9
- data/apartment.gemspec +2 -6
- data/lib/apartment.rb +5 -1
- data/lib/apartment/adapters/postgresql_adapter.rb +3 -2
- data/lib/apartment/elevators/domain.rb +3 -1
- data/lib/apartment/elevators/host.rb +30 -0
- data/lib/apartment/elevators/subdomain.rb +1 -1
- data/lib/apartment/tasks/enhancements.rb +36 -15
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +2 -0
- data/lib/tasks/apartment.rake +24 -5
- data/spec/tasks/apartment_rake_spec.rb +9 -0
- data/spec/unit/elevators/host_spec.rb +89 -0
- metadata +24 -8
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6db463e2bcd7fcb50414759a87c1b77ccb959e04
|
4
|
+
data.tar.gz: c614f5ba93fd4e5e779f07a08aaafa4118bd5025
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bacabc90c5c61c06b266bfa9bfb4d0cf0f3dedfcdba36362894848b065a5bcd6b174badf9d696a97aeadb7589d2063c3e28ef6249ec54bae721fa7914538fbc
|
7
|
+
data.tar.gz: b2a1c68f71969fd0e87bc0cfaebdcfd7f99ca54a5e815c2ae6dce17ab165c6352aa64624a29cad9311dd03925795c298828f35179448153d334f8a0c87b50469
|
@@ -0,0 +1,21 @@
|
|
1
|
+
## Steps to reproduce
|
2
|
+
|
3
|
+
## Expected behavior
|
4
|
+
|
5
|
+
## Actual behavior
|
6
|
+
|
7
|
+
## System configuration
|
8
|
+
|
9
|
+
<!-- Please let us know as far as you can. -->
|
10
|
+
|
11
|
+
* Database: (Tell us what database and its version you use.)
|
12
|
+
|
13
|
+
* Apartment version:
|
14
|
+
|
15
|
+
* Apartment config (in `config/initializers/apartment.rb` or so):
|
16
|
+
|
17
|
+
* `use_schemas`: (`true` or `false`)
|
18
|
+
|
19
|
+
* Rails (or ActiveRecord) version:
|
20
|
+
|
21
|
+
* Ruby version:
|
data/.travis.yml
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.0.0
|
4
3
|
- 2.1.9
|
5
4
|
- 2.2.4
|
6
5
|
- 2.3.1
|
@@ -26,12 +25,6 @@ matrix:
|
|
26
25
|
- rvm: ruby-head
|
27
26
|
- gemfile: gemfiles/rails_master.gemfile
|
28
27
|
exclude:
|
29
|
-
- rvm: 2.0.0
|
30
|
-
gemfile: gemfiles/rails_5_0.gemfile
|
31
|
-
- rvm: 2.0.0
|
32
|
-
gemfile: gemfiles/rails_5_1.gemfile
|
33
|
-
- rvm: 2.0.0
|
34
|
-
gemfile: gemfiles/rails_master.gemfile
|
35
28
|
- rvm: 2.1.9
|
36
29
|
gemfile: gemfiles/rails_5_0.gemfile
|
37
30
|
- rvm: 2.1.9
|
@@ -46,6 +39,8 @@ matrix:
|
|
46
39
|
gemfile: gemfiles/rails_4_0.gemfile
|
47
40
|
- rvm: ruby-head
|
48
41
|
gemfile: gemfiles/rails_4_1.gemfile
|
42
|
+
- rvm: jruby-9.0.5.0
|
43
|
+
gemfile: gemfiles/rails_4_0.gemfile
|
49
44
|
- rvm: jruby-9.0.5.0
|
50
45
|
gemfile: gemfiles/rails_4_2.gemfile
|
51
46
|
- rvm: jruby-9.0.5.0
|
@@ -54,6 +49,8 @@ matrix:
|
|
54
49
|
gemfile: gemfiles/rails_5_1.gemfile
|
55
50
|
- rvm: jruby-9.0.5.0
|
56
51
|
gemfile: gemfiles/rails_master.gemfile
|
52
|
+
- rvm: jruby-9.1.9.0
|
53
|
+
gemfile: gemfiles/rails_4_0.gemfile
|
57
54
|
- rvm: jruby-9.1.9.0
|
58
55
|
gemfile: gemfiles/rails_5_0.gemfile
|
59
56
|
- rvm: jruby-9.1.9.0
|
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -94,12 +94,17 @@ One can optionally use the full database creation instead if they want, though t
|
|
94
94
|
To switch tenants using Apartment, use the following command:
|
95
95
|
|
96
96
|
```ruby
|
97
|
-
Apartment::Tenant.switch
|
97
|
+
Apartment::Tenant.switch('tenant_name') do
|
98
|
+
# ...
|
99
|
+
end
|
98
100
|
```
|
99
101
|
|
100
102
|
When switch is called, all requests coming to ActiveRecord will be routed to the tenant
|
101
|
-
you specify (with the exception of excluded models, see below).
|
102
|
-
|
103
|
+
you specify (with the exception of excluded models, see below). The tenant is automatically
|
104
|
+
switched back at the end of the block to what it was before.
|
105
|
+
|
106
|
+
There is also `switch!` which doesn't take a block, but it's recommended to use `switch`.
|
107
|
+
To return to the default tenant, you can call `switch` with no arguments.
|
103
108
|
|
104
109
|
### Switching Tenants per request
|
105
110
|
|
@@ -117,7 +122,7 @@ manually in your `application.rb` like so
|
|
117
122
|
|
118
123
|
```ruby
|
119
124
|
# config/application.rb
|
120
|
-
require 'apartment/elevators/subdomain' # or 'domain'
|
125
|
+
require 'apartment/elevators/subdomain' # or 'domain', 'first_subdomain', 'host'
|
121
126
|
```
|
122
127
|
|
123
128
|
#### Switch on subdomain
|
@@ -155,7 +160,7 @@ module MyApplication
|
|
155
160
|
end
|
156
161
|
```
|
157
162
|
|
158
|
-
If you want to exclude a domain, for example if you don't want your application to
|
163
|
+
If you want to exclude a domain, for example if you don't want your application to treat www like a subdomain, in an initializer in your application, you can set the following:
|
159
164
|
|
160
165
|
```ruby
|
161
166
|
# config/initializers/apartment/subdomain_exclusions.rb
|
@@ -166,7 +171,7 @@ This functions much in the same way as the Subdomain elevator. **NOTE:** in fact
|
|
166
171
|
|
167
172
|
#### Switch on domain
|
168
173
|
|
169
|
-
To switch based on full domain (excluding
|
174
|
+
To switch based on full domain (excluding the 'www' subdomains and top level domains *ie '.com'* ) use the following:
|
170
175
|
|
171
176
|
```ruby
|
172
177
|
# application.rb
|
@@ -177,6 +182,11 @@ module MyApplication
|
|
177
182
|
end
|
178
183
|
```
|
179
184
|
|
185
|
+
Note that if you have several subdomains, then it will match on the first *non-www* subdomain:
|
186
|
+
- example.com => example
|
187
|
+
- www.example.com => example
|
188
|
+
- a.example.com => a
|
189
|
+
|
180
190
|
#### Switch on full host using a hash
|
181
191
|
|
182
192
|
To switch based on full host with a hash to find corresponding tenant name use the following:
|
@@ -190,6 +200,31 @@ module MyApplication
|
|
190
200
|
end
|
191
201
|
```
|
192
202
|
|
203
|
+
#### Switch on full host, ignoring given first subdomains
|
204
|
+
|
205
|
+
To switch based on full host to find corresponding tenant name use the following:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
# application.rb
|
209
|
+
module MyApplication
|
210
|
+
class Application < Rails::Application
|
211
|
+
config.middleware.use Apartment::Elevators::Host
|
212
|
+
end
|
213
|
+
end
|
214
|
+
```
|
215
|
+
|
216
|
+
If you want to exclude a first-subdomain, for example if you don't want your application to include www in the matching, in an initializer in your application, you can set the following:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
Apartment::Elevators::Host.ignored_first_subdomains = ['www']
|
220
|
+
```
|
221
|
+
|
222
|
+
With the above set, these would be the results:
|
223
|
+
- example.com => example.com
|
224
|
+
- www.example.com => example.com
|
225
|
+
- a.example.com => a.example.com
|
226
|
+
- www.a.example.com => a.example.com
|
227
|
+
|
193
228
|
#### Custom Elevator
|
194
229
|
|
195
230
|
A Generic Elevator exists that allows you to pass a `Proc` (or anything that responds to `call`) to the middleware. This Object will be passed in an `ActionDispatch::Request` object when called for you to do your magic. Apartment will use the return value of this proc to switch to the appropriate tenant. Use like so:
|
@@ -244,7 +279,7 @@ This works okay for simple applications, but it's important to consider that you
|
|
244
279
|
To resolve this issue, consider adding the Apartment middleware at a location in the Rack stack that makes sense for your needs, e.g.:
|
245
280
|
|
246
281
|
```ruby
|
247
|
-
Rails.application.config.middleware.insert_before
|
282
|
+
Rails.application.config.middleware.insert_before Warden::Manager, Apartment::Elevators::Subdomain
|
248
283
|
```
|
249
284
|
|
250
285
|
Now work done in the Warden middleware is wrapped in the `Apartment::Tenant.switch` context started in the Generic elevator.
|
@@ -342,6 +377,8 @@ namespace :db do
|
|
342
377
|
ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS HSTORE SCHEMA shared_extensions;'
|
343
378
|
# Enable UUID-OSSP
|
344
379
|
ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp" SCHEMA shared_extensions;'
|
380
|
+
# Grant usage to public
|
381
|
+
ActiveRecord::Base.connection.execute 'GRANT usage ON SCHEMA shared_extensions to public;'
|
345
382
|
end
|
346
383
|
end
|
347
384
|
|
@@ -443,6 +480,17 @@ Note that you can disable the default migrating of all tenants with `db:migrate`
|
|
443
480
|
`Apartment.db_migrate_tenants = false` in your `Rakefile`. Note this must be done
|
444
481
|
*before* the rake tasks are loaded. ie. before `YourApp::Application.load_tasks` is called
|
445
482
|
|
483
|
+
#### Parallel Migrations
|
484
|
+
|
485
|
+
Apartment supports parallelizing migrations into multiple threads when
|
486
|
+
you have a large number of tenants. By default, parallel migrations is
|
487
|
+
turned off. You can enable this by setting `parallel_migration_threads` to
|
488
|
+
the number of threads you want to use in your initializer.
|
489
|
+
|
490
|
+
Keep in mind that because migrations are going to access the database,
|
491
|
+
the number of threads indicated here should be less than the pool size
|
492
|
+
that Rails will use to connect to your database.
|
493
|
+
|
446
494
|
### Handling Environments
|
447
495
|
|
448
496
|
By default, when not using postgresql schemas, Apartment will prepend the environment to the tenant name
|
@@ -481,9 +529,9 @@ config.tenant_names = lambda do
|
|
481
529
|
end
|
482
530
|
```
|
483
531
|
|
484
|
-
##
|
532
|
+
## Background workers
|
485
533
|
|
486
|
-
|
534
|
+
See [apartment-sidekiq](https://github.com/influitive/apartment-sidekiq) or [apartment-activejob](https://github.com/influitive/apartment-activejob).
|
487
535
|
|
488
536
|
## Contributing
|
489
537
|
|
data/apartment.gemspec
CHANGED
@@ -21,7 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
# must be >= 3.1.2 due to bug in prepared_statements
|
22
22
|
s.add_dependency 'activerecord', '>= 3.1.2', '< 6.0'
|
23
23
|
s.add_dependency 'rack', '>= 1.3.6'
|
24
|
-
s.add_dependency 'public_suffix', '
|
24
|
+
s.add_dependency 'public_suffix', '>= 2'
|
25
|
+
s.add_dependency 'parallel', '>= 0.7.1'
|
25
26
|
|
26
27
|
s.add_development_dependency 'appraisal'
|
27
28
|
s.add_development_dependency 'rake', '~> 0.9'
|
@@ -41,9 +42,4 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.add_development_dependency 'pg', '>= 0.11.0'
|
42
43
|
s.add_development_dependency 'sqlite3'
|
43
44
|
end
|
44
|
-
|
45
|
-
if RUBY_VERSION < '2.1.0'
|
46
|
-
# capybara depends on xpath depends on nokogiri
|
47
|
-
s.add_development_dependency 'nokogiri', '< 1.7.0'
|
48
|
-
end
|
49
45
|
end
|
data/lib/apartment.rb
CHANGED
@@ -11,7 +11,7 @@ module Apartment
|
|
11
11
|
extend Forwardable
|
12
12
|
|
13
13
|
ACCESSOR_METHODS = [:use_schemas, :use_sql, :seed_after_create, :prepend_environment, :append_environment, :with_multi_server_setup ]
|
14
|
-
WRITER_METHODS = [:tenant_names, :database_schema_file, :excluded_models, :default_schema, :persistent_schemas, :connection_class, :tld_length, :db_migrate_tenants, :seed_data_file]
|
14
|
+
WRITER_METHODS = [:tenant_names, :database_schema_file, :excluded_models, :default_schema, :persistent_schemas, :connection_class, :tld_length, :db_migrate_tenants, :seed_data_file, :parallel_migration_threads]
|
15
15
|
|
16
16
|
attr_accessor(*ACCESSOR_METHODS)
|
17
17
|
attr_writer(*WRITER_METHODS)
|
@@ -51,6 +51,10 @@ module Apartment
|
|
51
51
|
def default_schema
|
52
52
|
@default_schema || "public" # TODO 'public' is postgres specific
|
53
53
|
end
|
54
|
+
|
55
|
+
def parallel_migration_threads
|
56
|
+
@parallel_migration_threads || 0
|
57
|
+
end
|
54
58
|
alias :default_tenant :default_schema
|
55
59
|
alias :default_tenant= :default_schema=
|
56
60
|
|
@@ -106,8 +106,9 @@ module Apartment
|
|
106
106
|
class PostgresqlSchemaFromSqlAdapter < PostgresqlSchemaAdapter
|
107
107
|
|
108
108
|
PSQL_DUMP_BLACKLISTED_STATEMENTS= [
|
109
|
-
/SET search_path/i,
|
110
|
-
/SET lock_timeout/i,
|
109
|
+
/SET search_path/i, # overridden later
|
110
|
+
/SET lock_timeout/i, # new in postgresql 9.3
|
111
|
+
/SET row_security/i, # new in postgresql 9.5
|
111
112
|
/SET idle_in_transaction_session_timeout/i, # new in postgresql 9.6
|
112
113
|
]
|
113
114
|
|
@@ -4,9 +4,11 @@ module Apartment
|
|
4
4
|
module Elevators
|
5
5
|
# Provides a rack based tenant switching solution based on domain
|
6
6
|
# Assumes that tenant name should match domain
|
7
|
-
# Parses request host for second level domain
|
7
|
+
# Parses request host for second level domain, ignoring www
|
8
8
|
# eg. example.com => example
|
9
9
|
# www.example.bc.ca => example
|
10
|
+
# a.example.bc.ca => a
|
11
|
+
#
|
10
12
|
#
|
11
13
|
class Domain < Generic
|
12
14
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'apartment/elevators/generic'
|
2
|
+
|
3
|
+
module Apartment
|
4
|
+
module Elevators
|
5
|
+
# Provides a rack based tenant switching solution based on the host
|
6
|
+
# Assumes that tenant name should match host
|
7
|
+
# Strips/ignores first subdomains in ignored_first_subdomains
|
8
|
+
# eg. example.com => example.com
|
9
|
+
# www.example.bc.ca => www.example.bc.ca
|
10
|
+
# if ignored_first_subdomains = ['www']
|
11
|
+
# www.example.bc.ca => example.bc.ca
|
12
|
+
# www.a.b.c.d.com => a.b.c.d.com
|
13
|
+
#
|
14
|
+
class Host < Generic
|
15
|
+
def self.ignored_first_subdomains
|
16
|
+
@ignored_first_subdomains ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.ignored_first_subdomains=(arg)
|
20
|
+
@ignored_first_subdomains = arg
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_tenant_name(request)
|
24
|
+
return nil if request.host.blank?
|
25
|
+
parts = request.host.split('.')
|
26
|
+
self.class.ignored_first_subdomains.include?(parts[0]) ? parts.drop(1).join('.') : request.host
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -3,33 +3,54 @@
|
|
3
3
|
|
4
4
|
module Apartment
|
5
5
|
class RakeTaskEnhancer
|
6
|
-
|
7
|
-
TASKS
|
8
|
-
|
6
|
+
|
7
|
+
module TASKS
|
8
|
+
ENHANCE_BEFORE = %w(db:drop)
|
9
|
+
ENHANCE_AFTER = %w(db:migrate db:rollback db:migrate:up db:migrate:down db:migrate:redo db:seed)
|
10
|
+
freeze
|
11
|
+
end
|
12
|
+
|
9
13
|
# This is a bit convoluted, but helps solve problems when using Apartment within an engine
|
10
14
|
# See spec/integration/use_within_an_engine.rb
|
11
|
-
|
15
|
+
|
12
16
|
class << self
|
13
17
|
def enhance!
|
14
|
-
|
18
|
+
return unless should_enhance?
|
19
|
+
|
20
|
+
# insert task before
|
21
|
+
TASKS::ENHANCE_BEFORE.each do |name|
|
15
22
|
task = Rake::Task[name]
|
16
|
-
task
|
17
|
-
if should_enhance?
|
18
|
-
enhance_task(task)
|
19
|
-
end
|
20
|
-
end
|
23
|
+
enhance_before_task(task)
|
21
24
|
end
|
25
|
+
|
26
|
+
# insert task after
|
27
|
+
TASKS::ENHANCE_AFTER.each do |name|
|
28
|
+
task = Rake::Task[name]
|
29
|
+
enhance_after_task(task)
|
30
|
+
end
|
31
|
+
|
22
32
|
end
|
23
|
-
|
33
|
+
|
24
34
|
def should_enhance?
|
25
35
|
Apartment.db_migrate_tenants
|
26
36
|
end
|
27
|
-
|
28
|
-
def
|
29
|
-
|
37
|
+
|
38
|
+
def enhance_before_task(task)
|
39
|
+
task.enhance([inserted_task_name(task)])
|
40
|
+
end
|
41
|
+
|
42
|
+
def enhance_after_task(task)
|
43
|
+
task.enhance do
|
44
|
+
Rake::Task[inserted_task_name(task)].invoke
|
45
|
+
end
|
30
46
|
end
|
47
|
+
|
48
|
+
def inserted_task_name(task)
|
49
|
+
task.name.sub(/db:/, 'apartment:')
|
50
|
+
end
|
51
|
+
|
31
52
|
end
|
32
|
-
|
53
|
+
|
33
54
|
end
|
34
55
|
end
|
35
56
|
|
data/lib/apartment/version.rb
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
# require 'apartment/elevators/domain'
|
7
7
|
require 'apartment/elevators/subdomain'
|
8
8
|
# require 'apartment/elevators/first_subdomain'
|
9
|
+
# require 'apartment/elevators/host'
|
9
10
|
|
10
11
|
#
|
11
12
|
# Apartment Configuration
|
@@ -95,3 +96,4 @@ end
|
|
95
96
|
# Rails.application.config.middleware.use Apartment::Elevators::Domain
|
96
97
|
Rails.application.config.middleware.use Apartment::Elevators::Subdomain
|
97
98
|
# Rails.application.config.middleware.use Apartment::Elevators::FirstSubdomain
|
99
|
+
# Rails.application.config.middleware.use Apartment::Elevators::Host
|
data/lib/tasks/apartment.rake
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'apartment/migrator'
|
2
|
+
require 'parallel'
|
2
3
|
|
3
4
|
apartment_namespace = namespace :apartment do
|
4
5
|
|
@@ -14,10 +15,22 @@ apartment_namespace = namespace :apartment do
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
desc "Drop all tenants"
|
19
|
+
task :drop do
|
20
|
+
tenants.each do |tenant|
|
21
|
+
begin
|
22
|
+
puts("Dropping #{tenant} tenant")
|
23
|
+
Apartment::Tenant.drop(tenant)
|
24
|
+
rescue Apartment::TenantNotFound => e
|
25
|
+
puts e.message
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
17
30
|
desc "Migrate all tenants"
|
18
31
|
task :migrate do
|
19
32
|
warn_if_tenants_empty
|
20
|
-
|
33
|
+
each_tenant do |tenant|
|
21
34
|
begin
|
22
35
|
puts("Migrating #{tenant} tenant")
|
23
36
|
Apartment::Migrator.migrate tenant
|
@@ -31,7 +44,7 @@ apartment_namespace = namespace :apartment do
|
|
31
44
|
task :seed do
|
32
45
|
warn_if_tenants_empty
|
33
46
|
|
34
|
-
|
47
|
+
each_tenant do |tenant|
|
35
48
|
begin
|
36
49
|
puts("Seeding #{tenant} tenant")
|
37
50
|
Apartment::Tenant.switch(tenant) do
|
@@ -49,7 +62,7 @@ apartment_namespace = namespace :apartment do
|
|
49
62
|
|
50
63
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
51
64
|
|
52
|
-
|
65
|
+
each_tenant do |tenant|
|
53
66
|
begin
|
54
67
|
puts("Rolling back #{tenant} tenant")
|
55
68
|
Apartment::Migrator.rollback tenant, step
|
@@ -67,7 +80,7 @@ apartment_namespace = namespace :apartment do
|
|
67
80
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
68
81
|
raise 'VERSION is required' unless version
|
69
82
|
|
70
|
-
|
83
|
+
each_tenant do |tenant|
|
71
84
|
begin
|
72
85
|
puts("Migrating #{tenant} tenant up")
|
73
86
|
Apartment::Migrator.run :up, tenant, version
|
@@ -84,7 +97,7 @@ apartment_namespace = namespace :apartment do
|
|
84
97
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
85
98
|
raise 'VERSION is required' unless version
|
86
99
|
|
87
|
-
|
100
|
+
each_tenant do |tenant|
|
88
101
|
begin
|
89
102
|
puts("Migrating #{tenant} tenant down")
|
90
103
|
Apartment::Migrator.run :down, tenant, version
|
@@ -106,6 +119,12 @@ apartment_namespace = namespace :apartment do
|
|
106
119
|
end
|
107
120
|
end
|
108
121
|
|
122
|
+
def each_tenant(&block)
|
123
|
+
Parallel.each(tenants, in_threads: Apartment.parallel_migration_threads) do |tenant|
|
124
|
+
block.call(tenant)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
109
128
|
def tenants
|
110
129
|
ENV['DB'] ? ENV['DB'].split(',').map { |s| s.strip } : Apartment.tenant_names || []
|
111
130
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'rake'
|
3
3
|
require 'apartment/migrator'
|
4
|
+
require 'apartment/tenant'
|
4
5
|
|
5
6
|
describe "apartment rake tasks" do
|
6
7
|
|
@@ -116,5 +117,13 @@ describe "apartment rake tasks" do
|
|
116
117
|
@rake['apartment:rollback'].invoke
|
117
118
|
end
|
118
119
|
end
|
120
|
+
|
121
|
+
describe "apartment:drop" do
|
122
|
+
it "should migrate public and all multi-tenant dbs" do
|
123
|
+
expect(Apartment::Tenant).to receive(:drop).exactly(tenant_count).times
|
124
|
+
@rake['apartment:drop'].invoke
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
119
128
|
end
|
120
129
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apartment/elevators/host'
|
3
|
+
|
4
|
+
describe Apartment::Elevators::Host do
|
5
|
+
|
6
|
+
subject(:elevator){ described_class.new(Proc.new{}) }
|
7
|
+
|
8
|
+
describe "#parse_tenant_name" do
|
9
|
+
|
10
|
+
it "should return nil when no host" do
|
11
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => '')
|
12
|
+
expect(elevator.parse_tenant_name(request)).to be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
context "assuming no ignored_first_subdomains" do
|
16
|
+
before { allow(described_class).to receive(:ignored_first_subdomains).and_return([]) }
|
17
|
+
|
18
|
+
context "with 3 parts" do
|
19
|
+
it "should return the whole host" do
|
20
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
|
21
|
+
expect(elevator.parse_tenant_name(request)).to eq('foo.bar.com')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with 6 parts" do
|
26
|
+
it "should return the whole host" do
|
27
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'one.two.three.foo.bar.com')
|
28
|
+
expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "assuming ignored_first_subdomains is set" do
|
34
|
+
before { allow(described_class).to receive(:ignored_first_subdomains).and_return(%w{www foo}) }
|
35
|
+
|
36
|
+
context "with 3 parts" do
|
37
|
+
it "should return host without www" do
|
38
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'www.bar.com')
|
39
|
+
expect(elevator.parse_tenant_name(request)).to eq('bar.com')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should return host without foo" do
|
43
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
|
44
|
+
expect(elevator.parse_tenant_name(request)).to eq('bar.com')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with 6 parts" do
|
49
|
+
it "should return host without www" do
|
50
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'www.one.two.three.foo.bar.com')
|
51
|
+
expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return host without www" do
|
55
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.one.two.three.bar.com')
|
56
|
+
expect(elevator.parse_tenant_name(request)).to eq('one.two.three.bar.com')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "assuming localhost" do
|
62
|
+
it "should return localhost" do
|
63
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost')
|
64
|
+
expect(elevator.parse_tenant_name(request)).to eq('localhost')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "assuming ip address" do
|
69
|
+
it "should return the ip address" do
|
70
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1')
|
71
|
+
expect(elevator.parse_tenant_name(request)).to eq('127.0.0.1')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#call" do
|
77
|
+
it "switches to the proper tenant" do
|
78
|
+
allow(described_class).to receive(:ignored_first_subdomains).and_return([])
|
79
|
+
expect(Apartment::Tenant).to receive(:switch).with('foo.bar.com')
|
80
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
81
|
+
end
|
82
|
+
|
83
|
+
it "ignores ignored_first_subdomains" do
|
84
|
+
allow(described_class).to receive(:ignored_first_subdomains).and_return(%w{foo})
|
85
|
+
expect(Apartment::Tenant).to receive(:switch).with('bar.com')
|
86
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
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: 2.
|
4
|
+
version: 2.1.0
|
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: 2017-
|
12
|
+
date: 2017-12-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -49,16 +49,30 @@ dependencies:
|
|
49
49
|
name: public_suffix
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2
|
54
|
+
version: '2'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: parallel
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.7.1
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
75
|
+
version: 0.7.1
|
62
76
|
- !ruby/object:Gem::Dependency
|
63
77
|
name: appraisal
|
64
78
|
requirement: !ruby/object:Gem::Requirement
|
@@ -180,11 +194,10 @@ executables: []
|
|
180
194
|
extensions: []
|
181
195
|
extra_rdoc_files: []
|
182
196
|
files:
|
197
|
+
- ".github/ISSUE_TEMPLATE.md"
|
183
198
|
- ".gitignore"
|
184
199
|
- ".pryrc"
|
185
200
|
- ".rspec"
|
186
|
-
- ".ruby-gemset"
|
187
|
-
- ".ruby-version"
|
188
201
|
- ".travis.yml"
|
189
202
|
- Appraisals
|
190
203
|
- Gemfile
|
@@ -215,6 +228,7 @@ files:
|
|
215
228
|
- lib/apartment/elevators/domain.rb
|
216
229
|
- lib/apartment/elevators/first_subdomain.rb
|
217
230
|
- lib/apartment/elevators/generic.rb
|
231
|
+
- lib/apartment/elevators/host.rb
|
218
232
|
- lib/apartment/elevators/host_hash.rb
|
219
233
|
- lib/apartment/elevators/subdomain.rb
|
220
234
|
- lib/apartment/migrator.rb
|
@@ -322,6 +336,7 @@ files:
|
|
322
336
|
- spec/unit/elevators/first_subdomain_spec.rb
|
323
337
|
- spec/unit/elevators/generic_spec.rb
|
324
338
|
- spec/unit/elevators/host_hash_spec.rb
|
339
|
+
- spec/unit/elevators/host_spec.rb
|
325
340
|
- spec/unit/elevators/subdomain_spec.rb
|
326
341
|
- spec/unit/migrator_spec.rb
|
327
342
|
- spec/unit/reloader_spec.rb
|
@@ -445,6 +460,7 @@ test_files:
|
|
445
460
|
- spec/unit/elevators/first_subdomain_spec.rb
|
446
461
|
- spec/unit/elevators/generic_spec.rb
|
447
462
|
- spec/unit/elevators/host_hash_spec.rb
|
463
|
+
- spec/unit/elevators/host_spec.rb
|
448
464
|
- spec/unit/elevators/subdomain_spec.rb
|
449
465
|
- spec/unit/migrator_spec.rb
|
450
466
|
- spec/unit/reloader_spec.rb
|
data/.ruby-gemset
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
apartment
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby-2.3
|