ros-apartment 2.3.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/.pryrc +5 -3
  3. data/.rubocop.yml +22 -0
  4. data/.rubocop_todo.yml +29 -0
  5. data/.story_branch.yml +5 -0
  6. data/.travis.yml +20 -36
  7. data/Appraisals +16 -29
  8. data/Gemfile +5 -2
  9. data/Guardfile +3 -1
  10. data/HISTORY.md +57 -0
  11. data/README.md +64 -21
  12. data/Rakefile +36 -22
  13. data/TODO.md +0 -1
  14. data/apartment.gemspec +17 -10
  15. data/gemfiles/rails_4_2.gemfile +12 -10
  16. data/gemfiles/rails_5_0.gemfile +2 -1
  17. data/gemfiles/rails_5_1.gemfile +2 -1
  18. data/gemfiles/rails_5_2.gemfile +2 -1
  19. data/gemfiles/rails_6_0.gemfile +6 -5
  20. data/gemfiles/rails_master.gemfile +2 -1
  21. data/lib/apartment.rb +38 -14
  22. data/lib/apartment/active_record/connection_handling.rb +17 -0
  23. data/lib/apartment/active_record/internal_metadata.rb +11 -0
  24. data/lib/apartment/active_record/log_subscriber.rb +41 -0
  25. data/lib/apartment/active_record/schema_migration.rb +13 -0
  26. data/lib/apartment/adapters/abstract_adapter.rb +49 -45
  27. data/lib/apartment/adapters/abstract_jdbc_adapter.rb +4 -3
  28. data/lib/apartment/adapters/jdbc_mysql_adapter.rb +3 -3
  29. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +20 -13
  30. data/lib/apartment/adapters/mysql2_adapter.rb +12 -9
  31. data/lib/apartment/adapters/postgis_adapter.rb +3 -2
  32. data/lib/apartment/adapters/postgresql_adapter.rb +59 -27
  33. data/lib/apartment/adapters/sqlite3_adapter.rb +18 -8
  34. data/lib/apartment/console.rb +35 -3
  35. data/lib/apartment/custom_console.rb +42 -0
  36. data/lib/apartment/deprecation.rb +2 -1
  37. data/lib/apartment/elevators/domain.rb +4 -3
  38. data/lib/apartment/elevators/first_subdomain.rb +3 -2
  39. data/lib/apartment/elevators/generic.rb +4 -3
  40. data/lib/apartment/elevators/host.rb +6 -1
  41. data/lib/apartment/elevators/host_hash.rb +6 -2
  42. data/lib/apartment/elevators/subdomain.rb +9 -5
  43. data/lib/apartment/migrator.rb +4 -3
  44. data/lib/apartment/model.rb +27 -0
  45. data/lib/apartment/railtie.rb +27 -15
  46. data/lib/apartment/reloader.rb +2 -1
  47. data/lib/apartment/tasks/enhancements.rb +4 -6
  48. data/lib/apartment/tasks/task_helper.rb +35 -0
  49. data/lib/apartment/tenant.rb +19 -9
  50. data/lib/apartment/version.rb +3 -1
  51. data/lib/generators/apartment/install/install_generator.rb +4 -3
  52. data/lib/generators/apartment/install/templates/apartment.rb +8 -2
  53. data/lib/tasks/apartment.rake +22 -44
  54. metadata +51 -230
  55. data/spec/adapters/jdbc_mysql_adapter_spec.rb +0 -19
  56. data/spec/adapters/jdbc_postgresql_adapter_spec.rb +0 -41
  57. data/spec/adapters/mysql2_adapter_spec.rb +0 -59
  58. data/spec/adapters/postgresql_adapter_spec.rb +0 -61
  59. data/spec/adapters/sqlite3_adapter_spec.rb +0 -83
  60. data/spec/apartment_spec.rb +0 -11
  61. data/spec/config/database.yml.sample +0 -49
  62. data/spec/dummy/Rakefile +0 -7
  63. data/spec/dummy/app/controllers/application_controller.rb +0 -6
  64. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  65. data/spec/dummy/app/models/company.rb +0 -3
  66. data/spec/dummy/app/models/user.rb +0 -3
  67. data/spec/dummy/app/views/application/index.html.erb +0 -1
  68. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  69. data/spec/dummy/config.ru +0 -4
  70. data/spec/dummy/config/application.rb +0 -49
  71. data/spec/dummy/config/boot.rb +0 -11
  72. data/spec/dummy/config/database.yml.sample +0 -44
  73. data/spec/dummy/config/environment.rb +0 -5
  74. data/spec/dummy/config/environments/development.rb +0 -28
  75. data/spec/dummy/config/environments/production.rb +0 -51
  76. data/spec/dummy/config/environments/test.rb +0 -34
  77. data/spec/dummy/config/initializers/apartment.rb +0 -4
  78. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  79. data/spec/dummy/config/initializers/inflections.rb +0 -10
  80. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  81. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  82. data/spec/dummy/config/initializers/session_store.rb +0 -8
  83. data/spec/dummy/config/locales/en.yml +0 -5
  84. data/spec/dummy/config/routes.rb +0 -3
  85. data/spec/dummy/db/migrate/20110613152810_create_dummy_models.rb +0 -39
  86. data/spec/dummy/db/migrate/20111202022214_create_table_books.rb +0 -14
  87. data/spec/dummy/db/migrate/20180415260934_create_public_tokens.rb +0 -13
  88. data/spec/dummy/db/schema.rb +0 -55
  89. data/spec/dummy/db/seeds.rb +0 -5
  90. data/spec/dummy/db/seeds/import.rb +0 -5
  91. data/spec/dummy/public/404.html +0 -26
  92. data/spec/dummy/public/422.html +0 -26
  93. data/spec/dummy/public/500.html +0 -26
  94. data/spec/dummy/public/favicon.ico +0 -0
  95. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  96. data/spec/dummy/script/rails +0 -6
  97. data/spec/dummy_engine/.gitignore +0 -8
  98. data/spec/dummy_engine/Gemfile +0 -15
  99. data/spec/dummy_engine/Rakefile +0 -34
  100. data/spec/dummy_engine/bin/rails +0 -12
  101. data/spec/dummy_engine/config/initializers/apartment.rb +0 -51
  102. data/spec/dummy_engine/dummy_engine.gemspec +0 -24
  103. data/spec/dummy_engine/lib/dummy_engine.rb +0 -4
  104. data/spec/dummy_engine/lib/dummy_engine/engine.rb +0 -4
  105. data/spec/dummy_engine/lib/dummy_engine/version.rb +0 -3
  106. data/spec/dummy_engine/test/dummy/Rakefile +0 -6
  107. data/spec/dummy_engine/test/dummy/config.ru +0 -4
  108. data/spec/dummy_engine/test/dummy/config/application.rb +0 -22
  109. data/spec/dummy_engine/test/dummy/config/boot.rb +0 -5
  110. data/spec/dummy_engine/test/dummy/config/database.yml +0 -25
  111. data/spec/dummy_engine/test/dummy/config/environment.rb +0 -5
  112. data/spec/dummy_engine/test/dummy/config/environments/development.rb +0 -37
  113. data/spec/dummy_engine/test/dummy/config/environments/production.rb +0 -78
  114. data/spec/dummy_engine/test/dummy/config/environments/test.rb +0 -39
  115. data/spec/dummy_engine/test/dummy/config/initializers/assets.rb +0 -8
  116. data/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  117. data/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  118. data/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  119. data/spec/dummy_engine/test/dummy/config/initializers/inflections.rb +0 -16
  120. data/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb +0 -4
  121. data/spec/dummy_engine/test/dummy/config/initializers/session_store.rb +0 -3
  122. data/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  123. data/spec/dummy_engine/test/dummy/config/locales/en.yml +0 -23
  124. data/spec/dummy_engine/test/dummy/config/routes.rb +0 -56
  125. data/spec/dummy_engine/test/dummy/config/secrets.yml +0 -22
  126. data/spec/examples/connection_adapter_examples.rb +0 -42
  127. data/spec/examples/generic_adapter_custom_configuration_example.rb +0 -95
  128. data/spec/examples/generic_adapter_examples.rb +0 -163
  129. data/spec/examples/schema_adapter_examples.rb +0 -234
  130. data/spec/integration/apartment_rake_integration_spec.rb +0 -107
  131. data/spec/integration/query_caching_spec.rb +0 -81
  132. data/spec/integration/use_within_an_engine_spec.rb +0 -28
  133. data/spec/schemas/v1.rb +0 -16
  134. data/spec/schemas/v2.rb +0 -43
  135. data/spec/schemas/v3.rb +0 -49
  136. data/spec/spec_helper.rb +0 -61
  137. data/spec/support/apartment_helpers.rb +0 -43
  138. data/spec/support/capybara_sessions.rb +0 -15
  139. data/spec/support/config.rb +0 -10
  140. data/spec/support/contexts.rb +0 -52
  141. data/spec/support/requirements.rb +0 -35
  142. data/spec/support/setup.rb +0 -46
  143. data/spec/tasks/apartment_rake_spec.rb +0 -129
  144. data/spec/tenant_spec.rb +0 -190
  145. data/spec/unit/config_spec.rb +0 -112
  146. data/spec/unit/elevators/domain_spec.rb +0 -32
  147. data/spec/unit/elevators/first_subdomain_spec.rb +0 -24
  148. data/spec/unit/elevators/generic_spec.rb +0 -54
  149. data/spec/unit/elevators/host_hash_spec.rb +0 -32
  150. data/spec/unit/elevators/host_spec.rb +0 -89
  151. data/spec/unit/elevators/subdomain_spec.rb +0 -76
  152. data/spec/unit/migrator_spec.rb +0 -77
  153. data/spec/unit/reloader_spec.rb +0 -24
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'apartment/elevators/generic'
2
4
 
3
5
  module Apartment
@@ -16,15 +18,18 @@ module Apartment
16
18
  @ignored_first_subdomains ||= []
17
19
  end
18
20
 
21
+ # rubocop:disable Style/TrivialAccessors
19
22
  def self.ignored_first_subdomains=(arg)
20
23
  @ignored_first_subdomains = arg
21
24
  end
25
+ # rubocop:enable Style/TrivialAccessors
22
26
 
23
27
  def parse_tenant_name(request)
24
28
  return nil if request.host.blank?
29
+
25
30
  parts = request.host.split('.')
26
31
  self.class.ignored_first_subdomains.include?(parts[0]) ? parts.drop(1).join('.') : request.host
27
32
  end
28
33
  end
29
34
  end
30
- end
35
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'apartment/elevators/generic'
2
4
 
3
5
  module Apartment
@@ -12,8 +14,10 @@ module Apartment
12
14
  end
13
15
 
14
16
  def parse_tenant_name(request)
15
- raise TenantNotFound,
16
- "Cannot find tenant for host #{request.host}" unless @hash.has_key?(request.host)
17
+ unless @hash.key?(request.host)
18
+ raise TenantNotFound,
19
+ "Cannot find tenant for host #{request.host}"
20
+ end
17
21
 
18
22
  @hash[request.host]
19
23
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'apartment/elevators/generic'
2
4
  require 'public_suffix'
3
5
 
@@ -11,9 +13,11 @@ module Apartment
11
13
  @excluded_subdomains ||= []
12
14
  end
13
15
 
16
+ # rubocop:disable Style/TrivialAccessors
14
17
  def self.excluded_subdomains=(arg)
15
18
  @excluded_subdomains = arg
16
19
  end
20
+ # rubocop:enable Style/TrivialAccessors
17
21
 
18
22
  def parse_tenant_name(request)
19
23
  request_subdomain = subdomain(request.host)
@@ -21,15 +25,15 @@ module Apartment
21
25
  # If the domain acquired is set to be excluded, set the tenant to whatever is currently
22
26
  # next in line in the schema search path.
23
27
  tenant = if self.class.excluded_subdomains.include?(request_subdomain)
24
- nil
25
- else
26
- request_subdomain
27
- end
28
+ nil
29
+ else
30
+ request_subdomain
31
+ end
28
32
 
29
33
  tenant.presence
30
34
  end
31
35
 
32
- protected
36
+ protected
33
37
 
34
38
  # *Almost* a direct ripoff of ActionDispatch::Request subdomain methods
35
39
 
@@ -1,16 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'apartment/tenant'
2
4
 
3
5
  module Apartment
4
6
  module Migrator
5
-
6
7
  extend self
7
8
 
8
9
  # Migrate to latest
9
10
  def migrate(database)
10
11
  Tenant.switch(database) do
11
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
12
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
12
13
 
13
- migration_scope_block = -> (migration) { ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope) }
14
+ migration_scope_block = ->(migration) { ENV['SCOPE'].blank? || (ENV['SCOPE'] == migration.scope) }
14
15
 
15
16
  if activerecord_below_5_2?
16
17
  ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, version, &migration_scope_block)
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apartment
4
+ module Model
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ # NOTE: key can either be an array of symbols or a single value.
9
+ # E.g. If we run the following query:
10
+ # `Setting.find_by(key: 'something', value: 'amazing')` key will have an array of symbols: `[:key, :something]`
11
+ # while if we run:
12
+ # `Setting.find(10)` key will have the value 'id'
13
+ def cached_find_by_statement(key, &block)
14
+ # Modifying the cache key to have a reference to the current tenant,
15
+ # so the cached statement is referring only to the tenant in which we've
16
+ # executed this
17
+ cache_key = if key.is_a? String
18
+ "#{Apartment::Tenant.current}_#{key}"
19
+ else
20
+ [Apartment::Tenant.current] + key
21
+ end
22
+ cache = @find_by_statement_cache[connection.prepared_statements]
23
+ cache.compute_if_absent(cache_key) { ActiveRecord::StatementCache.create(connection, &block) }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails'
2
4
  require 'apartment/tenant'
3
5
  require 'apartment/reloader'
4
6
 
5
7
  module Apartment
6
8
  class Railtie < Rails::Railtie
7
-
8
9
  #
9
10
  # Set up our default config options
10
11
  # Do this before the app initializers run so we don't override custom settings
@@ -17,27 +18,35 @@ module Apartment
17
18
  config.seed_after_create = false
18
19
  config.prepend_environment = false
19
20
  config.append_environment = false
21
+ config.tenant_presence_check = true
22
+ config.active_record_log = false
20
23
  end
21
24
 
22
25
  ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
23
26
  end
24
27
 
25
- # Hook into ActionDispatch::Reloader to ensure Apartment is properly initialized
26
- # Note that this doens't entirely work as expected in Development, because this is called before classes are reloaded
27
- # See the middleware/console declarations below to help with this. Hope to fix that soon.
28
- #
28
+ # Make sure Apartment is reconfigured when the code is reloaded
29
29
  config.to_prepare do
30
- next if ARGV.any? { |arg| arg =~ /\Aassets:(?:precompile|clean)\z/ }
30
+ Apartment::Tenant.reinitialize
31
+ end
31
32
 
32
- begin
33
- Apartment.connection_class.connection_pool.with_connection do
34
- Apartment::Tenant.init
33
+ #
34
+ # Ensure that Apartment::Tenant.init is called when
35
+ # a new connection is requested.
36
+ #
37
+ module ApartmentInitializer
38
+ def connection
39
+ super.tap do
40
+ Apartment::Tenant.init_once
35
41
  end
36
- rescue ::ActiveRecord::NoDatabaseError
37
- # Since `db:create` and other tasks invoke this block from Rails 5.2.0,
38
- # we need to swallow the error to execute `db:create` properly.
42
+ end
43
+
44
+ def arel_table
45
+ Apartment::Tenant.init_once
46
+ super
39
47
  end
40
48
  end
49
+ ActiveRecord::Base.singleton_class.prepend ApartmentInitializer
41
50
 
42
51
  #
43
52
  # Ensure rake tasks are loaded
@@ -48,8 +57,10 @@ module Apartment
48
57
  end
49
58
 
50
59
  #
51
- # The following initializers are a workaround to the fact that I can't properly hook into the rails reloader
52
- # Note this is technically valid for any environment where cache_classes is false, for us, it's just development
60
+ # The following initializers are a workaround to the fact that I can't
61
+ # properly hook into the rails reloader
62
+ # Note this is technically valid for any environment where cache_classes
63
+ # is false, for us, it's just development
53
64
  #
54
65
  if Rails.env.development?
55
66
 
@@ -58,7 +69,8 @@ module Apartment
58
69
  app.config.middleware.use Apartment::Reloader
59
70
  end
60
71
 
61
- # Overrides reload! to also call Apartment::Tenant.init as well so that the reloaded classes have the proper table_names
72
+ # Overrides reload! to also call Apartment::Tenant.init as well so that the
73
+ # reloaded classes have the proper table_names
62
74
  console do
63
75
  require 'apartment/console'
64
76
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Apartment
2
4
  class Reloader
3
-
4
5
  # Middleware used in development to init Apartment for each request
5
6
  # Necessary due to code reload (annoying). When models are reloaded, they no longer have the proper table_name
6
7
  # That is prepended with the schema (if using postgresql schemas)
@@ -1,12 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Require this file to append Apartment rake tasks to ActiveRecord db rake tasks
2
4
  # Enabled by default in the initializer
3
5
 
4
6
  module Apartment
5
7
  class RakeTaskEnhancer
6
-
7
8
  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)
9
+ ENHANCE_BEFORE = %w[db:drop].freeze
10
+ ENHANCE_AFTER = %w[db:create db:migrate db:rollback db:migrate:up db:migrate:down db:migrate:redo db:seed].freeze
10
11
  freeze
11
12
  end
12
13
 
@@ -28,7 +29,6 @@ module Apartment
28
29
  task = Rake::Task[name]
29
30
  enhance_after_task(task)
30
31
  end
31
-
32
32
  end
33
33
 
34
34
  def should_enhance?
@@ -48,9 +48,7 @@ module Apartment
48
48
  def inserted_task_name(task)
49
49
  task.name.sub(/db:/, 'apartment:')
50
50
  end
51
-
52
51
  end
53
-
54
52
  end
55
53
  end
56
54
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apartment
4
+ module TaskHelper
5
+ def self.each_tenant(&block)
6
+ Parallel.each(tenants_without_default, in_threads: Apartment.parallel_migration_threads) do |tenant|
7
+ block.call(tenant)
8
+ end
9
+ end
10
+
11
+ def self.tenants_without_default
12
+ tenants - [Apartment.default_tenant]
13
+ end
14
+
15
+ def self.tenants
16
+ ENV['DB'] ? ENV['DB'].split(',').map(&:strip) : Apartment.tenant_names || []
17
+ end
18
+
19
+ def self.warn_if_tenants_empty
20
+ return unless tenants.empty? && ENV['IGNORE_EMPTY_TENANTS'] != 'true'
21
+
22
+ # rubocop:disable Rails/Output
23
+ puts <<-WARNING
24
+ [WARNING] - The list of tenants to migrate appears to be empty. This could mean a few things:
25
+
26
+ 1. You may not have created any, in which case you can ignore this message
27
+ 2. You've run `apartment:migrate` directly without loading the Rails environment
28
+ * `apartment:migrate` is now deprecated. Tenants will automatically be migrated with `db:migrate`
29
+
30
+ Note that your tenants currently haven't been migrated. You'll need to run `db:migrate` to rectify this.
31
+ WARNING
32
+ # rubocop:enable Rails/Output
33
+ end
34
+ end
35
+ end
@@ -1,21 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  module Apartment
4
6
  # The main entry point to Apartment functions
5
7
  #
6
8
  module Tenant
7
-
8
9
  extend self
9
10
  extend Forwardable
10
11
 
11
- def_delegators :adapter, :create, :drop, :switch, :switch!, :current, :each, :reset, :set_callback, :seed, :current_tenant, :default_tenant, :environmentify
12
+ def_delegators :adapter, :create, :drop, :switch, :switch!, :current, :each,
13
+ :reset, :init, :set_callback, :seed, :current_tenant,
14
+ :default_tenant, :environmentify
12
15
 
13
16
  attr_writer :config
14
17
 
15
- # Initialize Apartment config options such as excluded_models
16
- #
17
- def init
18
- adapter.process_excluded_models
18
+ def init_once
19
+ return if @already_initialized
20
+
21
+ # To avoid infinite loops in work init is doing,
22
+ # we need to set @already_initialized to true
23
+ # before init is called
24
+ @already_initialized = true
25
+ init
26
+ end
27
+
28
+ def reinitialize
29
+ @already_initialized = false
19
30
  end
20
31
 
21
32
  # Fetch the proper multi-tenant adapter based on Rails config
@@ -40,9 +51,7 @@ module Apartment
40
51
  raise "The adapter `#{adapter_method}` is not yet supported"
41
52
  end
42
53
 
43
- unless respond_to?(adapter_method)
44
- raise AdapterNotFound, "database configuration specifies nonexistent #{config[:adapter]} adapter"
45
- end
54
+ raise AdapterNotFound, "database configuration specifies nonexistent #{config[:adapter]} adapter" unless respond_to?(adapter_method)
46
55
 
47
56
  send(adapter_method, config)
48
57
  end
@@ -52,6 +61,7 @@ module Apartment
52
61
  #
53
62
  def reload!(config = nil)
54
63
  Thread.current[:apartment_adapter] = nil
64
+ reinitialize
55
65
  @config = config
56
66
  end
57
67
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Apartment
2
- VERSION = "2.3.0"
4
+ VERSION = '2.7.0'
3
5
  end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Apartment
2
4
  class InstallGenerator < Rails::Generators::Base
3
- source_root File.expand_path('../templates', __FILE__)
5
+ source_root File.expand_path('templates', __dir__)
4
6
 
5
7
  def copy_files
6
- template "apartment.rb", File.join("config", "initializers", "apartment.rb")
8
+ template 'apartment.rb', File.join('config', 'initializers', 'apartment.rb')
7
9
  end
8
-
9
10
  end
10
11
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # You can have Apartment route to the appropriate Tenant by adding some Rack middleware.
2
4
  # Apartment can support many different "Elevators" that can take care of this routing to your data.
3
5
  # Require whichever Elevator you're using below or none if you have a custom one.
@@ -12,7 +14,6 @@ require 'apartment/elevators/subdomain'
12
14
  # Apartment Configuration
13
15
  #
14
16
  Apartment.configure do |config|
15
-
16
17
  # Add any models that you do not want to be multi-tenanted, but remain in the global (public) namespace.
17
18
  # A typical example would be a Customer or Tenant model that stores each Tenant's information.
18
19
  #
@@ -48,7 +49,7 @@ Apartment.configure do |config|
48
49
  # end
49
50
  # end
50
51
  #
51
- config.tenant_names = lambda { ToDo_Tenant_Or_User_Model.pluck :database }
52
+ config.tenant_names = -> { ToDo_Tenant_Or_User_Model.pluck :database }
52
53
 
53
54
  # PostgreSQL:
54
55
  # Specifies whether to use PostgreSQL schemas or create a new database per Tenant.
@@ -95,6 +96,11 @@ Apartment.configure do |config|
95
96
  # the new tenant
96
97
  #
97
98
  # config.pg_excluded_names = ["uuid_generate_v4"]
99
+
100
+ # Specifies whether the database and schema (when using PostgreSQL schemas) will prepend in ActiveRecord log.
101
+ # Uncomment the line below if you want to enable this behavior.
102
+ #
103
+ # config.active_record_log = true
98
104
  end
99
105
 
100
106
  # Setup a custom Tenant switching middleware. The Proc should return the name of the Tenant that
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'apartment/migrator'
4
+ require 'apartment/tasks/task_helper'
2
5
  require 'parallel'
3
6
 
4
7
  apartment_namespace = namespace :apartment do
5
-
6
- desc "Create all tenants"
8
+ desc 'Create all tenants'
7
9
  task :create do
8
- tenants.each do |tenant|
10
+ Apartment::TaskHelper.tenants.each do |tenant|
9
11
  begin
10
12
  puts("Creating #{tenant} tenant")
11
13
  Apartment::Tenant.create(tenant)
@@ -15,22 +17,22 @@ apartment_namespace = namespace :apartment do
15
17
  end
16
18
  end
17
19
 
18
- desc "Drop all tenants"
20
+ desc 'Drop all tenants'
19
21
  task :drop do
20
- tenants.each do |tenant|
22
+ Apartment::TaskHelper.tenants.each do |tenant|
21
23
  begin
22
24
  puts("Dropping #{tenant} tenant")
23
25
  Apartment::Tenant.drop(tenant)
24
- rescue Apartment::TenantNotFound => e
26
+ rescue Apartment::TenantNotFound, ActiveRecord::NoDatabaseError => e
25
27
  puts e.message
26
28
  end
27
29
  end
28
30
  end
29
31
 
30
- desc "Migrate all tenants"
32
+ desc 'Migrate all tenants'
31
33
  task :migrate do
32
- warn_if_tenants_empty
33
- each_tenant do |tenant|
34
+ Apartment::TaskHelper.warn_if_tenants_empty
35
+ Apartment::TaskHelper.each_tenant do |tenant|
34
36
  begin
35
37
  puts("Migrating #{tenant} tenant")
36
38
  Apartment::Migrator.migrate tenant
@@ -40,11 +42,11 @@ apartment_namespace = namespace :apartment do
40
42
  end
41
43
  end
42
44
 
43
- desc "Seed all tenants"
45
+ desc 'Seed all tenants'
44
46
  task :seed do
45
- warn_if_tenants_empty
47
+ Apartment::TaskHelper.warn_if_tenants_empty
46
48
 
47
- each_tenant do |tenant|
49
+ Apartment::TaskHelper.each_tenant do |tenant|
48
50
  begin
49
51
  puts("Seeding #{tenant} tenant")
50
52
  Apartment::Tenant.switch(tenant) do
@@ -56,13 +58,13 @@ apartment_namespace = namespace :apartment do
56
58
  end
57
59
  end
58
60
 
59
- desc "Rolls the migration back to the previous version (specify steps w/ STEP=n) across all tenants."
61
+ desc 'Rolls the migration back to the previous version (specify steps w/ STEP=n) across all tenants.'
60
62
  task :rollback do
61
- warn_if_tenants_empty
63
+ Apartment::TaskHelper.warn_if_tenants_empty
62
64
 
63
65
  step = ENV['STEP'] ? ENV['STEP'].to_i : 1
64
66
 
65
- each_tenant do |tenant|
67
+ Apartment::TaskHelper.each_tenant do |tenant|
66
68
  begin
67
69
  puts("Rolling back #{tenant} tenant")
68
70
  Apartment::Migrator.rollback tenant, step
@@ -75,12 +77,12 @@ apartment_namespace = namespace :apartment do
75
77
  namespace :migrate do
76
78
  desc 'Runs the "up" for a given migration VERSION across all tenants.'
77
79
  task :up do
78
- warn_if_tenants_empty
80
+ Apartment::TaskHelper.warn_if_tenants_empty
79
81
 
80
82
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
81
83
  raise 'VERSION is required' unless version
82
84
 
83
- each_tenant do |tenant|
85
+ Apartment::TaskHelper.each_tenant do |tenant|
84
86
  begin
85
87
  puts("Migrating #{tenant} tenant up")
86
88
  Apartment::Migrator.run :up, tenant, version
@@ -92,12 +94,12 @@ apartment_namespace = namespace :apartment do
92
94
 
93
95
  desc 'Runs the "down" for a given migration VERSION across all tenants.'
94
96
  task :down do
95
- warn_if_tenants_empty
97
+ Apartment::TaskHelper.warn_if_tenants_empty
96
98
 
97
99
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
98
100
  raise 'VERSION is required' unless version
99
101
 
100
- each_tenant do |tenant|
102
+ Apartment::TaskHelper.each_tenant do |tenant|
101
103
  begin
102
104
  puts("Migrating #{tenant} tenant down")
103
105
  Apartment::Migrator.run :down, tenant, version
@@ -107,7 +109,7 @@ apartment_namespace = namespace :apartment do
107
109
  end
108
110
  end
109
111
 
110
- desc 'Rolls back the tenant one migration and re migrate up (options: STEP=x, VERSION=x).'
112
+ desc 'Rolls back the tenant one migration and re migrate up (options: STEP=x, VERSION=x).'
111
113
  task :redo do
112
114
  if ENV['VERSION']
113
115
  apartment_namespace['migrate:down'].invoke
@@ -118,28 +120,4 @@ apartment_namespace = namespace :apartment do
118
120
  end
119
121
  end
120
122
  end
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
-
128
- def tenants
129
- ENV['DB'] ? ENV['DB'].split(',').map { |s| s.strip } : Apartment.tenant_names || []
130
- end
131
-
132
- def warn_if_tenants_empty
133
- if tenants.empty? && ENV['IGNORE_EMPTY_TENANTS'] != "true"
134
- puts <<-WARNING
135
- [WARNING] - The list of tenants to migrate appears to be empty. This could mean a few things:
136
-
137
- 1. You may not have created any, in which case you can ignore this message
138
- 2. You've run `apartment:migrate` directly without loading the Rails environment
139
- * `apartment:migrate` is now deprecated. Tenants will automatically be migrated with `db:migrate`
140
-
141
- Note that your tenants currently haven't been migrated. You'll need to run `db:migrate` to rectify this.
142
- WARNING
143
- end
144
- end
145
123
  end