ros-apartment 2.3.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +78 -0
  3. data/.github/workflows/changelog.yml +63 -0
  4. data/.github/workflows/reviewdog.yml +22 -0
  5. data/.pryrc +5 -3
  6. data/.rubocop.yml +32 -0
  7. data/.rubocop_todo.yml +233 -0
  8. data/.ruby-version +1 -0
  9. data/.story_branch.yml +5 -0
  10. data/Appraisals +29 -42
  11. data/CHANGELOG.md +963 -0
  12. data/Gemfile +2 -7
  13. data/Guardfile +3 -16
  14. data/HISTORY.md +159 -68
  15. data/README.md +101 -21
  16. data/Rakefile +39 -22
  17. data/TODO.md +0 -1
  18. data/gemfiles/rails_5_2.gemfile +0 -5
  19. data/gemfiles/rails_6_0.gemfile +4 -9
  20. data/gemfiles/rails_6_1.gemfile +17 -0
  21. data/gemfiles/rails_7_0.gemfile +17 -0
  22. data/gemfiles/rails_master.gemfile +3 -8
  23. data/lib/apartment/active_record/connection_handling.rb +20 -0
  24. data/lib/apartment/active_record/internal_metadata.rb +9 -0
  25. data/lib/apartment/active_record/postgresql_adapter.rb +39 -0
  26. data/lib/apartment/active_record/schema_migration.rb +11 -0
  27. data/lib/apartment/adapters/abstract_adapter.rb +52 -46
  28. data/lib/apartment/adapters/abstract_jdbc_adapter.rb +5 -3
  29. data/lib/apartment/adapters/jdbc_mysql_adapter.rb +3 -3
  30. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +19 -13
  31. data/lib/apartment/adapters/mysql2_adapter.rb +15 -9
  32. data/lib/apartment/adapters/postgis_adapter.rb +3 -2
  33. data/lib/apartment/adapters/postgresql_adapter.rb +79 -31
  34. data/lib/apartment/adapters/sqlite3_adapter.rb +18 -8
  35. data/lib/apartment/console.rb +23 -11
  36. data/lib/apartment/custom_console.rb +42 -0
  37. data/lib/apartment/deprecation.rb +2 -1
  38. data/lib/apartment/elevators/domain.rb +4 -3
  39. data/lib/apartment/elevators/first_subdomain.rb +3 -2
  40. data/lib/apartment/elevators/generic.rb +4 -3
  41. data/lib/apartment/elevators/host.rb +6 -1
  42. data/lib/apartment/elevators/host_hash.rb +6 -2
  43. data/lib/apartment/elevators/subdomain.rb +9 -5
  44. data/lib/apartment/log_subscriber.rb +33 -0
  45. data/lib/apartment/migrator.rb +4 -3
  46. data/lib/apartment/model.rb +29 -0
  47. data/lib/apartment/railtie.rb +16 -20
  48. data/lib/apartment/tasks/enhancements.rb +4 -6
  49. data/lib/apartment/tasks/task_helper.rb +52 -0
  50. data/lib/apartment/tenant.rb +7 -10
  51. data/lib/apartment/version.rb +3 -1
  52. data/lib/apartment.rb +56 -15
  53. data/lib/generators/apartment/install/install_generator.rb +4 -3
  54. data/lib/generators/apartment/install/templates/apartment.rb +10 -3
  55. data/lib/tasks/apartment.rake +48 -87
  56. data/ros-apartment.gemspec +59 -0
  57. metadata +148 -240
  58. data/.travis.yml +0 -65
  59. data/apartment.gemspec +0 -47
  60. data/gemfiles/rails_4_2.gemfile +0 -23
  61. data/gemfiles/rails_5_0.gemfile +0 -22
  62. data/gemfiles/rails_5_1.gemfile +0 -22
  63. data/lib/apartment/reloader.rb +0 -21
  64. data/spec/adapters/jdbc_mysql_adapter_spec.rb +0 -19
  65. data/spec/adapters/jdbc_postgresql_adapter_spec.rb +0 -41
  66. data/spec/adapters/mysql2_adapter_spec.rb +0 -59
  67. data/spec/adapters/postgresql_adapter_spec.rb +0 -61
  68. data/spec/adapters/sqlite3_adapter_spec.rb +0 -83
  69. data/spec/apartment_spec.rb +0 -11
  70. data/spec/config/database.yml.sample +0 -49
  71. data/spec/dummy/Rakefile +0 -7
  72. data/spec/dummy/app/controllers/application_controller.rb +0 -6
  73. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  74. data/spec/dummy/app/models/company.rb +0 -3
  75. data/spec/dummy/app/models/user.rb +0 -3
  76. data/spec/dummy/app/views/application/index.html.erb +0 -1
  77. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  78. data/spec/dummy/config/application.rb +0 -49
  79. data/spec/dummy/config/boot.rb +0 -11
  80. data/spec/dummy/config/database.yml.sample +0 -44
  81. data/spec/dummy/config/environment.rb +0 -5
  82. data/spec/dummy/config/environments/development.rb +0 -28
  83. data/spec/dummy/config/environments/production.rb +0 -51
  84. data/spec/dummy/config/environments/test.rb +0 -34
  85. data/spec/dummy/config/initializers/apartment.rb +0 -4
  86. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  87. data/spec/dummy/config/initializers/inflections.rb +0 -10
  88. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  89. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  90. data/spec/dummy/config/initializers/session_store.rb +0 -8
  91. data/spec/dummy/config/locales/en.yml +0 -5
  92. data/spec/dummy/config/routes.rb +0 -3
  93. data/spec/dummy/config.ru +0 -4
  94. data/spec/dummy/db/migrate/20110613152810_create_dummy_models.rb +0 -39
  95. data/spec/dummy/db/migrate/20111202022214_create_table_books.rb +0 -14
  96. data/spec/dummy/db/migrate/20180415260934_create_public_tokens.rb +0 -13
  97. data/spec/dummy/db/schema.rb +0 -55
  98. data/spec/dummy/db/seeds/import.rb +0 -5
  99. data/spec/dummy/db/seeds.rb +0 -5
  100. data/spec/dummy/db/test.sqlite3 +0 -0
  101. data/spec/dummy/public/404.html +0 -26
  102. data/spec/dummy/public/422.html +0 -26
  103. data/spec/dummy/public/500.html +0 -26
  104. data/spec/dummy/public/favicon.ico +0 -0
  105. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  106. data/spec/dummy/script/rails +0 -6
  107. data/spec/dummy_engine/.gitignore +0 -8
  108. data/spec/dummy_engine/Gemfile +0 -15
  109. data/spec/dummy_engine/Rakefile +0 -34
  110. data/spec/dummy_engine/bin/rails +0 -12
  111. data/spec/dummy_engine/config/initializers/apartment.rb +0 -51
  112. data/spec/dummy_engine/dummy_engine.gemspec +0 -24
  113. data/spec/dummy_engine/lib/dummy_engine/engine.rb +0 -4
  114. data/spec/dummy_engine/lib/dummy_engine/version.rb +0 -3
  115. data/spec/dummy_engine/lib/dummy_engine.rb +0 -4
  116. data/spec/dummy_engine/test/dummy/Rakefile +0 -6
  117. data/spec/dummy_engine/test/dummy/config/application.rb +0 -22
  118. data/spec/dummy_engine/test/dummy/config/boot.rb +0 -5
  119. data/spec/dummy_engine/test/dummy/config/database.yml +0 -25
  120. data/spec/dummy_engine/test/dummy/config/environment.rb +0 -5
  121. data/spec/dummy_engine/test/dummy/config/environments/development.rb +0 -37
  122. data/spec/dummy_engine/test/dummy/config/environments/production.rb +0 -78
  123. data/spec/dummy_engine/test/dummy/config/environments/test.rb +0 -39
  124. data/spec/dummy_engine/test/dummy/config/initializers/assets.rb +0 -8
  125. data/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  126. data/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  127. data/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  128. data/spec/dummy_engine/test/dummy/config/initializers/inflections.rb +0 -16
  129. data/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb +0 -4
  130. data/spec/dummy_engine/test/dummy/config/initializers/session_store.rb +0 -3
  131. data/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  132. data/spec/dummy_engine/test/dummy/config/locales/en.yml +0 -23
  133. data/spec/dummy_engine/test/dummy/config/routes.rb +0 -56
  134. data/spec/dummy_engine/test/dummy/config/secrets.yml +0 -22
  135. data/spec/dummy_engine/test/dummy/config.ru +0 -4
  136. data/spec/examples/connection_adapter_examples.rb +0 -42
  137. data/spec/examples/generic_adapter_custom_configuration_example.rb +0 -95
  138. data/spec/examples/generic_adapter_examples.rb +0 -163
  139. data/spec/examples/schema_adapter_examples.rb +0 -234
  140. data/spec/integration/apartment_rake_integration_spec.rb +0 -107
  141. data/spec/integration/query_caching_spec.rb +0 -81
  142. data/spec/integration/use_within_an_engine_spec.rb +0 -28
  143. data/spec/schemas/v1.rb +0 -16
  144. data/spec/schemas/v2.rb +0 -43
  145. data/spec/schemas/v3.rb +0 -49
  146. data/spec/spec_helper.rb +0 -61
  147. data/spec/support/apartment_helpers.rb +0 -43
  148. data/spec/support/capybara_sessions.rb +0 -15
  149. data/spec/support/config.rb +0 -10
  150. data/spec/support/contexts.rb +0 -52
  151. data/spec/support/requirements.rb +0 -35
  152. data/spec/support/setup.rb +0 -46
  153. data/spec/tasks/apartment_rake_spec.rb +0 -129
  154. data/spec/tenant_spec.rb +0 -190
  155. data/spec/unit/config_spec.rb +0 -112
  156. data/spec/unit/elevators/domain_spec.rb +0 -32
  157. data/spec/unit/elevators/first_subdomain_spec.rb +0 -24
  158. data/spec/unit/elevators/generic_spec.rb +0 -54
  159. data/spec/unit/elevators/host_hash_spec.rb +0 -32
  160. data/spec/unit/elevators/host_spec.rb +0 -89
  161. data/spec/unit/elevators/subdomain_spec.rb +0 -76
  162. data/spec/unit/migrator_spec.rb +0 -77
  163. data/spec/unit/reloader_spec.rb +0 -24
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Apartment
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/apartment.svg)](https://badge.fury.io/rb/apartment)
4
- [![Code Climate](https://codeclimate.com/github/influitive/apartment/badges/gpa.svg)](https://codeclimate.com/github/influitive/apartment)
5
- [![Build Status](https://travis-ci.org/influitive/apartment.svg?branch=development)](https://travis-ci.org/influitive/apartment)
3
+ [![Gem Version](https://badge.fury.io/rb/ros-apartment.svg)](https://badge.fury.io/rb/apartment)
4
+ [![Code Climate](https://api.codeclimate.com/v1/badges/b0dc327380bb8438f991/maintainability)](https://codeclimate.com/github/rails-on-services/apartment/maintainability)
5
+ [![Build Status](https://travis-ci.org/rails-on-services/apartment.svg?branch=development)](https://travis-ci.org/rails-on-services/apartment)
6
6
 
7
7
  *Multitenancy for Rails and ActiveRecord*
8
8
 
@@ -33,7 +33,7 @@ may find or proposing improvements to the gem itself. Feel free to reach out.
33
33
  Add the following to your Gemfile:
34
34
 
35
35
  ```ruby
36
- gem 'ros-apartment'
36
+ gem 'ros-apartment', require: 'apartment'
37
37
  ```
38
38
 
39
39
  Then generate your `Apartment` config file using
@@ -101,6 +101,16 @@ switched back at the end of the block to what it was before.
101
101
  There is also `switch!` which doesn't take a block, but it's recommended to use `switch`.
102
102
  To return to the default tenant, you can call `switch` with no arguments.
103
103
 
104
+ #### Multiple Tenants
105
+
106
+ When using schemas, you can also pass in a list of schemas if desired. Any tables defined in a schema earlier in the chain will be referenced first, so this is only useful if you have a schema with only some of the tables defined:
107
+
108
+ ```ruby
109
+ Apartment::Tenant.switch(['tenant_1', 'tenant_2']) do
110
+ # ...
111
+ end
112
+ ```
113
+
104
114
  ### Switching Tenants per request
105
115
 
106
116
  You can have Apartment route to the appropriate tenant by adding some Rack middleware.
@@ -229,7 +239,7 @@ A Generic Elevator exists that allows you to pass a `Proc` (or anything that res
229
239
  module MyApplication
230
240
  class Application < Rails::Application
231
241
  # Obviously not a contrived example
232
- config.middleware.use Apartment::Elevators::Generic, Proc.new { |request| request.host.reverse }
242
+ config.middleware.use Apartment::Elevators::Generic, proc { |request| request.host.reverse }
233
243
  end
234
244
  end
235
245
  ```
@@ -289,6 +299,27 @@ Apartment::Tenant.drop('tenant_name')
289
299
 
290
300
  When method is called, the schema is dropped and all data from itself will be lost. Be careful with this method.
291
301
 
302
+ ### Custom Prompt
303
+
304
+ #### Console methods
305
+
306
+ `ros-apartment` console configures two helper methods:
307
+ 1. `tenant_list` - list available tenants while using the console
308
+ 2. `st(tenant_name:String)` - Switches the context to the tenant name passed, if
309
+ it exists.
310
+
311
+ #### Custom printed prompt
312
+
313
+ `ros-apartment` also has a custom prompt that gives a bit more information about
314
+ the context in which you're running. It shows the environment as well as the tenant
315
+ that is currently switched to. In order for you to enable this, you need to require
316
+ the custom console in your application.
317
+
318
+ In `application.rb` add `require 'apartment/custom_console'`.
319
+ Please note that we rely on `pry-rails` to edit the prompt, thus your project needs
320
+ to install it as well. In order to do so, you need to add `gem 'pry-rails'` to your
321
+ project's gemfile.
322
+
292
323
  ## Config
293
324
 
294
325
  The following config options should be set up in a Rails initializer such as:
@@ -303,6 +334,37 @@ Apartment.configure do |config|
303
334
  end
304
335
  ```
305
336
 
337
+ ### Skip tenant schema check
338
+
339
+ This is configurable by setting: `tenant_presence_check`. It defaults to true
340
+ in order to maintain the original gem behavior. This is only checked when using one of the PostgreSQL adapters.
341
+ The original gem behavior, when running `switch` would look for the existence of the schema before switching. This adds an extra query on every context switch. While in the default simple scenarios this is a valid check, in high volume platforms this adds some unnecessary overhead which can be detected in some other ways on the application level.
342
+
343
+ Setting this configuration value to `false` will disable the schema presence check before trying to switch the context.
344
+
345
+ ```ruby
346
+ Apartment.configure do |config|
347
+ config.tenant_presence_check = false
348
+ end
349
+ ```
350
+
351
+ ### Additional logging information
352
+
353
+ Enabling this configuration will output the database that the process is currently connected to as well as which
354
+ schemas are in the search path. This can be enabled by setting to true the `active_record_log` configuration.
355
+
356
+ Please note that our custom logger inherits from `ActiveRecord::LogSubscriber` so this will be required for the configuration to work.
357
+
358
+ **Example log output:**
359
+
360
+ <img src="documentation/images/log_example.png">
361
+
362
+ ```ruby
363
+ Apartment.configure do |config|
364
+ config.active_record_log = true
365
+ end
366
+ ```
367
+
306
368
  ### Excluding models
307
369
 
308
370
  If you have some models that should always access the 'public' tenant, you can specify this by configuring Apartment using `Apartment.configure`. This will yield a config object for you. You can set excluded models like so:
@@ -320,17 +382,30 @@ Rails will always access the 'public' tenant when accessing these models, but no
320
382
 
321
383
  ### Postgresql Schemas
322
384
 
323
- ## Providing a Different default_schema
385
+ #### Alternative: Creating new schemas by using raw SQL dumps
386
+
387
+ Apartment can be forced to use raw SQL dumps insted of `schema.rb` for creating new schemas. Use this when you are using some extra features in postgres that can't be represented in `schema.rb`, like materialized views etc.
388
+
389
+ This only applies while using postgres adapter and `config.use_schemas` is set to `true`.
390
+ (Note: this option doesn't use `db/structure.sql`, it creates SQL dump by executing `pg_dump`)
391
+
392
+ Enable this option with:
393
+
394
+ ```ruby
395
+ config.use_sql = true
396
+ ```
397
+
398
+ ### Providing a Different default_tenant
324
399
 
325
400
  By default, ActiveRecord will use `"$user", public` as the default `schema_search_path`. This can be modified if you wish to use a different default schema be setting:
326
401
 
327
402
  ```ruby
328
- config.default_schema = "some_other_schema"
403
+ config.default_tenant = "some_other_schema"
329
404
  ```
330
405
 
331
406
  With that set, all excluded models will use this schema as the table name prefix instead of `public` and `reset` on `Apartment::Tenant` will return to this schema as well.
332
407
 
333
- ## Persistent Schemas
408
+ ### Persistent Schemas
334
409
 
335
410
  Apartment will normally just switch the `schema_search_path` whole hog to the one passed in. This can lead to problems if you want other schemas to always be searched as well. Enter `persistent_schemas`. You can configure a list of other schemas that will always remain in the search path, while the default gets swapped out:
336
411
 
@@ -398,7 +473,7 @@ schema_search_path: "public,shared_extensions"
398
473
  ...
399
474
  ```
400
475
 
401
- This would be for a config with `default_schema` set to `public` and `persistent_schemas` set to `['shared_extensions']`. **Note**: This only works on Heroku with [Rails 4.1+](https://devcenter.heroku.com/changelog-items/426). For apps that use older Rails versions hosted on Heroku, the only way to properly setup is to start with a fresh PostgreSQL instance:
476
+ This would be for a config with `default_tenant` set to `public` and `persistent_schemas` set to `['shared_extensions']`. **Note**: This only works on Heroku with [Rails 4.1+](https://devcenter.heroku.com/changelog-items/426). For apps that use older Rails versions hosted on Heroku, the only way to properly setup is to start with a fresh PostgreSQL instance:
402
477
 
403
478
  1. Append `?schema_search_path=public,hstore` to your `DATABASE_URL` environment variable, by this you don't have to revise the `database.yml` file (which is impossible since Heroku regenerates a completely different and immutable `database.yml` of its own on each deploy)
404
479
  2. Run `heroku pg:psql` from your command line
@@ -436,18 +511,6 @@ schema in the `search_path` at all times. We won't be able to do this though unt
436
511
  also contain the tenanted tables, which is an open issue with no real milestone to be completed.
437
512
  Happy to accept PR's on the matter.
438
513
 
439
- #### Alternative: Creating new schemas by using raw SQL dumps
440
-
441
- Apartment can be forced to use raw SQL dumps insted of `schema.rb` for creating new schemas. Use this when you are using some extra features in postgres that can't be represented in `schema.rb`, like materialized views etc.
442
-
443
- This only applies while using postgres adapter and `config.use_schemas` is set to `true`.
444
- (Note: this option doesn't use `db/structure.sql`, it creates SQL dump by executing `pg_dump`)
445
-
446
- Enable this option with:
447
- ```ruby
448
- config.use_sql = true
449
- ```
450
-
451
514
  ### Managing Migrations
452
515
 
453
516
  In order to migrate all of your tenants (or postgresql schemas) you need to provide a list
@@ -558,6 +621,16 @@ module Apartment
558
621
  end
559
622
  ```
560
623
 
624
+ ## Running rails console without a connection to the database
625
+
626
+ By default, once apartment starts, it establishes a connection to the database. It is possible to
627
+ disable this initial connection, by running with `APARTMENT_DISABLE_INIT` set to something:
628
+
629
+ ```shell
630
+ $ APARTMENT_DISABLE_INIT=true DATABASE_URL=postgresql://localhost:1234/buk_development bin/rails runner 'puts 1'
631
+ # 1
632
+ ```
633
+
561
634
  ## Contributing
562
635
 
563
636
  * In both `spec/dummy/config` and `spec/config`, you will see `database.yml.sample` files
@@ -569,6 +642,13 @@ end
569
642
 
570
643
  * If you're looking to help, check out the TODO file for some upcoming changes I'd like to implement in Apartment.
571
644
 
645
+ ### Running bundle install
646
+
647
+ mysql2 gem in some cases fails to install.
648
+ If you face problems running bundle install in OSX, try installing the gem running:
649
+
650
+ `gem install mysql2 -v '0.5.3' -- --with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include`
651
+
572
652
  ## License
573
653
 
574
654
  Apartment is released under the [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,19 +1,25 @@
1
- require 'bundler' rescue 'You must `gem install bundler` and `bundle install` to run rake tasks'
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'bundler'
5
+ rescue StandardError
6
+ 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
2
8
  Bundler.setup
3
9
  Bundler::GemHelper.install_tasks
4
10
 
5
11
  require 'appraisal'
6
12
 
7
- require "rspec"
8
- require "rspec/core/rake_task"
13
+ require 'rspec'
14
+ require 'rspec/core/rake_task'
9
15
 
10
- RSpec::Core::RakeTask.new(:spec => %w{ db:copy_credentials db:test:prepare }) do |spec|
11
- spec.pattern = "spec/**/*_spec.rb"
16
+ RSpec::Core::RakeTask.new(spec: %w[db:copy_credentials db:test:prepare]) do |spec|
17
+ spec.pattern = 'spec/**/*_spec.rb'
12
18
  # spec.rspec_opts = '--order rand:47078'
13
19
  end
14
20
 
15
21
  namespace :spec do
16
- [:tasks, :unit, :adapters, :integration].each do |type|
22
+ %i[tasks unit adapters integration].each do |type|
17
23
  RSpec::Core::RakeTask.new(type => :spec) do |spec|
18
24
  spec.pattern = "spec/#{type}/**/*_spec.rb"
19
25
  end
@@ -27,11 +33,11 @@ task :console do
27
33
  Pry.start
28
34
  end
29
35
 
30
- task :default => :spec
36
+ task default: :spec
31
37
 
32
38
  namespace :db do
33
39
  namespace :test do
34
- task :prepare => %w{postgres:drop_db postgres:build_db mysql:drop_db mysql:build_db}
40
+ task prepare: %w[postgres:drop_db postgres:build_db mysql:drop_db mysql:build_db]
35
41
  end
36
42
 
37
43
  desc "copy sample database credential files over if real files don't exist"
@@ -40,29 +46,36 @@ namespace :db do
40
46
  apartment_db_file = 'spec/config/database.yml'
41
47
  rails_db_file = 'spec/dummy/config/database.yml'
42
48
 
43
- FileUtils.copy(apartment_db_file + '.sample', apartment_db_file, :verbose => true) unless File.exists?(apartment_db_file)
44
- FileUtils.copy(rails_db_file + '.sample', rails_db_file, :verbose => true) unless File.exists?(rails_db_file)
49
+ unless File.exist?(apartment_db_file)
50
+ FileUtils.copy("#{apartment_db_file}.sample", apartment_db_file, verbose: true)
51
+ end
52
+ FileUtils.copy("#{rails_db_file}.sample", rails_db_file, verbose: true) unless File.exist?(rails_db_file)
45
53
  end
46
54
  end
47
55
 
48
56
  namespace :postgres do
49
57
  require 'active_record'
50
- require "#{File.join(File.dirname(__FILE__), 'spec', 'support', 'config')}"
58
+ require File.join(File.dirname(__FILE__), 'spec', 'support', 'config').to_s
51
59
 
52
60
  desc 'Build the PostgreSQL test databases'
53
61
  task :build_db do
54
62
  params = []
55
- params << "-E UTF8"
63
+ params << '-E UTF8'
56
64
  params << pg_config['database']
57
65
  params << "-U#{pg_config['username']}"
58
66
  params << "-h#{pg_config['host']}" if pg_config['host']
59
67
  params << "-p#{pg_config['port']}" if pg_config['port']
60
- %x{ createdb #{params.join(' ')} } rescue "test db already exists"
68
+
69
+ begin
70
+ `createdb #{params.join(' ')}`
71
+ rescue StandardError
72
+ 'test db already exists'
73
+ end
61
74
  ActiveRecord::Base.establish_connection pg_config
62
75
  migrate
63
76
  end
64
77
 
65
- desc "drop the PostgreSQL test database"
78
+ desc 'drop the PostgreSQL test database'
66
79
  task :drop_db do
67
80
  puts "dropping database #{pg_config['database']}"
68
81
  params = []
@@ -70,14 +83,13 @@ namespace :postgres do
70
83
  params << "-U#{pg_config['username']}"
71
84
  params << "-h#{pg_config['host']}" if pg_config['host']
72
85
  params << "-p#{pg_config['port']}" if pg_config['port']
73
- %x{ dropdb #{params.join(' ')} }
86
+ `dropdb #{params.join(' ')}`
74
87
  end
75
-
76
88
  end
77
89
 
78
90
  namespace :mysql do
79
91
  require 'active_record'
80
- require "#{File.join(File.dirname(__FILE__), 'spec', 'support', 'config')}"
92
+ require File.join(File.dirname(__FILE__), 'spec', 'support', 'config').to_s
81
93
 
82
94
  desc 'Build the MySQL test databases'
83
95
  task :build_db do
@@ -85,24 +97,29 @@ namespace :mysql do
85
97
  params << "-h #{my_config['host']}" if my_config['host']
86
98
  params << "-u #{my_config['username']}" if my_config['username']
87
99
  params << "-p#{my_config['password']}" if my_config['password']
88
- %x{ mysqladmin #{params.join(' ')} create #{my_config['database']} } rescue "test db already exists"
100
+ params << "--port #{my_config['port']}" if my_config['port']
101
+ begin
102
+ `mysqladmin #{params.join(' ')} create #{my_config['database']}`
103
+ rescue StandardError
104
+ 'test db already exists'
105
+ end
89
106
  ActiveRecord::Base.establish_connection my_config
90
107
  migrate
91
108
  end
92
109
 
93
- desc "drop the MySQL test database"
110
+ desc 'drop the MySQL test database'
94
111
  task :drop_db do
95
112
  puts "dropping database #{my_config['database']}"
96
113
  params = []
97
114
  params << "-h #{my_config['host']}" if my_config['host']
98
115
  params << "-u #{my_config['username']}" if my_config['username']
99
116
  params << "-p#{my_config['password']}" if my_config['password']
100
- %x{ mysqladmin #{params.join(' ')} drop #{my_config['database']} --force}
117
+ params << "--port #{my_config['port']}" if my_config['port']
118
+ `mysqladmin #{params.join(' ')} drop #{my_config['database']} --force`
101
119
  end
102
-
103
120
  end
104
121
 
105
- # TODO clean this up
122
+ # TODO: clean this up
106
123
  def config
107
124
  Apartment::Test.config['connections']
108
125
  end
data/TODO.md CHANGED
@@ -46,6 +46,5 @@
46
46
 
47
47
  Quick TODOs
48
48
 
49
- 1. `default_tenant` should be up to the adapter, not the Apartment class, deprecate `default_schema`
50
49
  2. deprecation.rb rescues everything, we have a hard dependency on ActiveSupport so this is unnecessary
51
50
  3.
@@ -4,11 +4,6 @@ source "http://rubygems.org"
4
4
 
5
5
  gem "rails", "~> 5.2.0"
6
6
 
7
- group :local do
8
- gem "pry"
9
- gem "guard-rspec", "~> 4.2"
10
- end
11
-
12
7
  platforms :jruby do
13
8
  gem "activerecord-jdbc-adapter", "~> 52.0"
14
9
  gem "activerecord-jdbcpostgresql-adapter", "~> 52.0"
@@ -2,21 +2,16 @@
2
2
 
3
3
  source "http://rubygems.org"
4
4
 
5
- gem "rails", "~> 6.0.0.rc1"
6
-
7
- group :local do
8
- gem "pry"
9
- gem "guard-rspec", "~> 4.2"
10
- end
5
+ gem "rails", "~> 6.0.0"
11
6
 
12
7
  platforms :ruby do
13
8
  gem "sqlite3", "~> 1.4"
14
9
  end
15
10
 
16
11
  platforms :jruby do
17
- gem "activerecord-jdbc-adapter", "~> 60.0.rc1"
18
- gem "activerecord-jdbcpostgresql-adapter", "~> 60.0.rc1"
19
- gem "activerecord-jdbcmysql-adapter", "~> 60.0.rc1"
12
+ gem "activerecord-jdbc-adapter", "~> 60.0"
13
+ gem "activerecord-jdbcpostgresql-adapter", "~> 60.0"
14
+ gem "activerecord-jdbcmysql-adapter", "~> 60.0"
20
15
  end
21
16
 
22
17
  gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rails", "~> 6.1.0"
6
+
7
+ platforms :ruby do
8
+ gem "sqlite3", "~> 1.4"
9
+ end
10
+
11
+ platforms :jruby do
12
+ gem "activerecord-jdbc-adapter", "~> 61.0"
13
+ gem "activerecord-jdbcpostgresql-adapter", "~> 61.0"
14
+ gem "activerecord-jdbcmysql-adapter", "~> 61.0"
15
+ end
16
+
17
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rails", "~> 7.0.0"
6
+
7
+ platforms :ruby do
8
+ gem "sqlite3", "~> 1.4"
9
+ end
10
+
11
+ platforms :jruby do
12
+ gem "activerecord-jdbc-adapter", "~> 61.0"
13
+ gem "activerecord-jdbcpostgresql-adapter", "~> 61.0"
14
+ gem "activerecord-jdbcmysql-adapter", "~> 61.0"
15
+ end
16
+
17
+ gemspec path: "../"
@@ -4,19 +4,14 @@ source "http://rubygems.org"
4
4
 
5
5
  gem "rails", git: "https://github.com/rails/rails.git"
6
6
 
7
- group :local do
8
- gem "pry"
9
- gem "guard-rspec", "~> 4.2"
10
- end
11
-
12
7
  platforms :ruby do
13
8
  gem "sqlite3", "~> 1.4"
14
9
  end
15
10
 
16
11
  platforms :jruby do
17
- gem "activerecord-jdbc-adapter", "~> 52.0"
18
- gem "activerecord-jdbcpostgresql-adapter", "~> 52.0"
19
- gem "activerecord-jdbcmysql-adapter", "~> 52.0"
12
+ gem "activerecord-jdbc-adapter", "~> 61.0"
13
+ gem "activerecord-jdbcpostgresql-adapter", "~> 61.0"
14
+ gem "activerecord-jdbcmysql-adapter", "~> 61.0"
20
15
  end
21
16
 
22
17
  gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # This is monkeypatching activerecord to ensure that whenever a new connection is established it
5
+ # switches to the same tenant as before the connection switching. This problem is more evident when
6
+ # using read replica in Rails 6
7
+ module ConnectionHandling
8
+ def connected_to_with_tenant(database: nil, role: nil, prevent_writes: false, &blk)
9
+ current_tenant = Apartment::Tenant.current
10
+
11
+ connected_to_without_tenant(database: database, role: role, prevent_writes: prevent_writes) do
12
+ Apartment::Tenant.switch!(current_tenant)
13
+ yield(blk)
14
+ end
15
+ end
16
+
17
+ alias connected_to_without_tenant connected_to
18
+ alias connected_to connected_to_with_tenant
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class InternalMetadata < ActiveRecord::Base # :nodoc:
4
+ class << self
5
+ def table_exists?
6
+ connection.table_exists?(table_name)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/ClassAndModuleChildren
4
+
5
+ # NOTE: This patch is meant to remove any schema_prefix appart from the ones for
6
+ # excluded models. The schema_prefix would be resolved by apartment's setting
7
+ # of search path
8
+ module Apartment::PostgreSqlAdapterPatch
9
+ def default_sequence_name(table, _column)
10
+ res = super
11
+ schema_prefix = "#{Apartment::Tenant.current}."
12
+ default_tenant_prefix = "#{Apartment::Tenant.default_tenant}."
13
+
14
+ # NOTE: Excluded models should always access the sequence from the default
15
+ # tenant schema
16
+ if excluded_model?(table)
17
+ res.sub!(schema_prefix, default_tenant_prefix) if schema_prefix != default_tenant_prefix
18
+ return res
19
+ end
20
+
21
+ res.delete_prefix!(schema_prefix) if res&.starts_with?(schema_prefix)
22
+
23
+ res
24
+ end
25
+
26
+ private
27
+
28
+ def excluded_model?(table)
29
+ Apartment.excluded_models.any? { |m| m.constantize.table_name == table }
30
+ end
31
+ end
32
+
33
+ require 'active_record/connection_adapters/postgresql_adapter'
34
+
35
+ # NOTE: inject this into postgresql adapters
36
+ class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
37
+ include Apartment::PostgreSqlAdapterPatch
38
+ end
39
+ # rubocop:enable Style/ClassAndModuleChildren
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class SchemaMigration < ActiveRecord::Base # :nodoc:
5
+ class << self
6
+ def table_exists?
7
+ connection.table_exists?(table_name)
8
+ end
9
+ end
10
+ end
11
+ end