apartment 0.26.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.ruby-version +1 -1
- data/.travis.yml +9 -0
- data/HISTORY.md +8 -0
- data/README.md +30 -7
- data/TODO.md +9 -0
- data/apartment.gemspec +9 -8
- data/lib/apartment.rb +9 -18
- data/lib/apartment/adapters/abstract_adapter.rb +63 -30
- data/lib/apartment/adapters/jdbc_mysql_adapter.rb +2 -2
- data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +3 -3
- data/lib/apartment/adapters/mysql2_adapter.rb +10 -6
- data/lib/apartment/adapters/postgresql_adapter.rb +15 -21
- data/lib/apartment/adapters/sqlite3_adapter.rb +4 -4
- data/lib/apartment/deprecation.rb +13 -0
- data/lib/apartment/elevators/generic.rb +3 -2
- data/lib/apartment/elevators/host_hash.rb +1 -1
- data/lib/apartment/migrator.rb +3 -3
- data/lib/apartment/tasks/enhancements.rb +31 -21
- data/lib/apartment/tenant.rb +10 -7
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +41 -22
- data/lib/tasks/apartment.rake +1 -1
- data/spec/adapters/jdbc_mysql_adapter_spec.rb +1 -1
- data/spec/adapters/jdbc_postgresql_adapter_spec.rb +2 -2
- data/spec/adapters/mysql2_adapter_spec.rb +4 -2
- data/spec/adapters/postgresql_adapter_spec.rb +3 -3
- data/spec/adapters/sqlite3_adapter_spec.rb +1 -1
- data/spec/dummy_engine/.gitignore +8 -0
- data/spec/dummy_engine/Gemfile +15 -0
- data/spec/dummy_engine/Rakefile +34 -0
- data/spec/dummy_engine/bin/rails +12 -0
- data/spec/dummy_engine/config/initializers/apartment.rb +51 -0
- data/spec/dummy_engine/dummy_engine.gemspec +24 -0
- data/spec/dummy_engine/lib/dummy_engine.rb +4 -0
- data/spec/dummy_engine/lib/dummy_engine/engine.rb +4 -0
- data/spec/dummy_engine/lib/dummy_engine/version.rb +3 -0
- data/spec/dummy_engine/test/dummy/Rakefile +6 -0
- data/spec/dummy_engine/test/dummy/config.ru +4 -0
- data/spec/dummy_engine/test/dummy/config/application.rb +22 -0
- data/spec/dummy_engine/test/dummy/config/boot.rb +5 -0
- data/spec/dummy_engine/test/dummy/config/database.yml +25 -0
- data/spec/dummy_engine/test/dummy/config/environment.rb +5 -0
- data/spec/dummy_engine/test/dummy/config/environments/development.rb +37 -0
- data/spec/dummy_engine/test/dummy/config/environments/production.rb +78 -0
- data/spec/dummy_engine/test/dummy/config/environments/test.rb +39 -0
- data/spec/dummy_engine/test/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy_engine/test/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy_engine/test/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy_engine/test/dummy/config/locales/en.yml +23 -0
- data/spec/dummy_engine/test/dummy/config/routes.rb +56 -0
- data/spec/dummy_engine/test/dummy/config/secrets.yml +22 -0
- data/spec/examples/connection_adapter_examples.rb +5 -5
- data/spec/examples/generic_adapter_examples.rb +75 -37
- data/spec/examples/schema_adapter_examples.rb +19 -24
- data/spec/integration/query_caching_spec.rb +3 -3
- data/spec/integration/use_within_an_engine_spec.rb +28 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/setup.rb +9 -9
- data/spec/{database_spec.rb → tenant_spec.rb} +20 -30
- data/spec/unit/config_spec.rb +2 -2
- data/spec/unit/elevators/domain_spec.rb +1 -1
- data/spec/unit/elevators/generic_spec.rb +2 -2
- data/spec/unit/elevators/host_hash_spec.rb +5 -5
- data/spec/unit/elevators/subdomain_spec.rb +2 -2
- data/spec/unit/migrator_spec.rb +7 -7
- metadata +104 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50bc04fb2abdbb0df0af4569c5452b9afeff250f
|
4
|
+
data.tar.gz: 3ba7ad62f8a6bc517e75d42e752a87786df87822
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02bd472cb4382a949ce4058359bfff9c6320b5f65d2d3d86a4bc0b34a25c81b9750d8a950a28df4d1ae32e691dd7441340b7136ae9d6bd48f8cf80f11d29a390
|
7
|
+
data.tar.gz: 29a933a4e09c7e681d99bbd7bf44c0cd590a9c8b80dc9ed20b7bcafa11b61ce4dfd837896036e14ca31c5c4c8ef83b27dfb134ea9e09518855845d8c26970c6e
|
data/.rspec
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.1
|
data/.travis.yml
CHANGED
@@ -3,7 +3,9 @@ rvm:
|
|
3
3
|
- 1.9.3
|
4
4
|
- 2.0.0
|
5
5
|
- 2.1.0
|
6
|
+
- 2.2.0
|
6
7
|
- jruby-19mode
|
8
|
+
- jruby-head
|
7
9
|
gemfile:
|
8
10
|
- gemfiles/rails_3_2.gemfile
|
9
11
|
- gemfiles/rails_4_0.gemfile
|
@@ -15,3 +17,10 @@ before_install:
|
|
15
17
|
env:
|
16
18
|
RUBY_GC_MALLOC_LIMIT: 90000000
|
17
19
|
RUBY_FREE_MIN: 200000
|
20
|
+
matrix:
|
21
|
+
allow_failures:
|
22
|
+
- rvm: jruby-head
|
23
|
+
exclude:
|
24
|
+
- rvm: 2.2.0
|
25
|
+
gemfile: gemfiles/rails_3_2.gemfile
|
26
|
+
fast_finish: true
|
data/HISTORY.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 1.0.0
|
2
|
+
* Feb 3, 2015
|
3
|
+
|
4
|
+
- [BREAKING CHANGE] `Apartment::Tenant.process` is deprecated in favour of `Apartment::Tenant.switch`
|
5
|
+
- [BREAKING CHANGE] `Apartment::Tenant.switch` without a block is deprecated in favour of `Apartment::Tenant.switch!`
|
6
|
+
- Raise proper `TenantNotFound`, `TenantExists` exceptions
|
7
|
+
- Deprecate old `SchemaNotFound`, `DatabaseNotFound` exceptions
|
8
|
+
|
1
9
|
# 0.26.1
|
2
10
|
* Jan 13, 2015
|
3
11
|
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ Configure as needed using the docs below.
|
|
31
31
|
That's all you need to set up the Apartment libraries. If you want to switch tenants
|
32
32
|
on a per-user basis, look under "Usage - Switching tenants per request", below.
|
33
33
|
|
34
|
-
> NOTE: If using [
|
34
|
+
> NOTE: If using [postgresql schemas](http://www.postgresql.org/docs/9.0/static/ddl-schemas.html) you must use:
|
35
35
|
>
|
36
36
|
> * for Rails 3.1.x: _Rails ~> 3.1.2_, it contains a [patch](https://github.com/rails/rails/pull/3232) that makes prepared statements work with multiple schemas
|
37
37
|
|
@@ -67,7 +67,7 @@ One can optionally use the full database creation instead if they want, though t
|
|
67
67
|
To switch tenants using Apartment, use the following command:
|
68
68
|
|
69
69
|
```ruby
|
70
|
-
Apartment::Tenant.switch('tenant_name')
|
70
|
+
Apartment::Tenant.switch!('tenant_name')
|
71
71
|
```
|
72
72
|
|
73
73
|
When switch is called, all requests coming to ActiveRecord will be routed to the tenant
|
@@ -148,6 +148,29 @@ module MyApplication
|
|
148
148
|
end
|
149
149
|
```
|
150
150
|
|
151
|
+
Your other option is to subclass the Generic elevator and implement your own
|
152
|
+
switching mechanism. This is exactly how the other elevators work. Look at
|
153
|
+
the `subdomain.rb` elevator to get an idea of how this should work. Basically
|
154
|
+
all you need to do is subclass the generic elevator and implement your own
|
155
|
+
`parse_tenant_name` method that will ultimately return the name of the tenant
|
156
|
+
based on the request being made. It *could* look something like this:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
# app/middleware/my_custom_elevator.rb
|
160
|
+
class MyCustomElevator < Apartment::Elevators::Generic
|
161
|
+
|
162
|
+
# @return {String} - The tenant to switch to
|
163
|
+
def parse_tenant_name(request)
|
164
|
+
# request is an instance of Rack::Request
|
165
|
+
|
166
|
+
# example: look up some tenant from the db based on this request
|
167
|
+
tenant_name = SomeModel.from_request(request)
|
168
|
+
|
169
|
+
return tenant_name
|
170
|
+
end
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
151
174
|
## Config
|
152
175
|
|
153
176
|
The following config options should be set up in a Rails initializer such as:
|
@@ -196,12 +219,12 @@ config.persistent_schemas = ['some', 'other', 'schemas']
|
|
196
219
|
```
|
197
220
|
|
198
221
|
### Installing Extensions into Persistent Schemas
|
199
|
-
Persistent Schemas have numerous useful applications. [Hstore](http://www.postgresql.org/docs/9.1/static/hstore.html), for instance, is a popular storage engine for Postgresql. In order to use extensions such as Hstore, you have to install it to a specific schema and have that always in the `schema_search_path`.
|
222
|
+
Persistent Schemas have numerous useful applications. [Hstore](http://www.postgresql.org/docs/9.1/static/hstore.html), for instance, is a popular storage engine for Postgresql. In order to use extensions such as Hstore, you have to install it to a specific schema and have that always in the `schema_search_path`.
|
200
223
|
|
201
224
|
When using extensions, keep in mind:
|
202
225
|
* Extensions can only be installed into one schema per database, so we will want to install it into a schema that is always available in the `schema_search_path`
|
203
|
-
* The schema and extension need to be created in the database *before* they are referenced in migrations, database.yml or apartment.
|
204
|
-
* There does not seem to be a way to create the schema and extension using standard rails migrations.
|
226
|
+
* The schema and extension need to be created in the database *before* they are referenced in migrations, database.yml or apartment.
|
227
|
+
* There does not seem to be a way to create the schema and extension using standard rails migrations.
|
205
228
|
* Rails db:test:prepare deletes and recreates the database, so it needs to be easy for the extension schema to be recreated here.
|
206
229
|
|
207
230
|
#### 1. Ensure the extensions schema is created when the database is created
|
@@ -243,7 +266,7 @@ end
|
|
243
266
|
|
244
267
|
#### 2. Ensure the schema is in Rails' default connection
|
245
268
|
|
246
|
-
Next, your `database.yml` file must mimic what you've set for your default and persistent schemas in Apartment. When you run
|
269
|
+
Next, your `database.yml` file must mimic what you've set for your default and persistent schemas in Apartment. When you run migrations with Rails, it won't know about the extensions schema because Apartment isn't injected into the default connection, it's done on a per-request basis, therefore Rails doesn't know about `hstore` or `uuid-ossp` during migrations. To do so, add the following to your `database.yml` for all environments
|
247
270
|
|
248
271
|
```yaml
|
249
272
|
# database.yml
|
@@ -253,7 +276,7 @@ schema_search_path: "public,shared_extensions"
|
|
253
276
|
...
|
254
277
|
```
|
255
278
|
|
256
|
-
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/
|
279
|
+
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:
|
257
280
|
|
258
281
|
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)
|
259
282
|
2. Run `heroku pg:psql` from your command line
|
data/TODO.md
CHANGED
@@ -40,3 +40,12 @@
|
|
40
40
|
|
41
41
|
9. This one is pretty lofty, but I'd also like to abstract out the fact that Apartment uses ActiveRecord. With the new DataMapper coming out soon and other popular
|
42
42
|
DBMS's (ie. mongo, couch etc...), it'd be nice if Apartment could be the de-facto interface for multi-tenancy on these systems.
|
43
|
+
|
44
|
+
|
45
|
+
===================
|
46
|
+
|
47
|
+
Quick TODOs
|
48
|
+
|
49
|
+
1. `default_tenant` should be up to the adapter, not the Apartment class, deprecate `default_schema`
|
50
|
+
2. deprecation.rb rescues everything, we have a hard dependency on ActiveSupport so this is unnecessary
|
51
|
+
3.
|
data/apartment.gemspec
CHANGED
@@ -23,25 +23,26 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
Apartment Deprecation Warning
|
25
25
|
|
26
|
-
`Apartment::
|
27
|
-
|
28
|
-
appropriate abstraction.
|
26
|
+
`Apartment::Tenant.process` has been deprecated in favour of `Apartment::Tenant.switch`.
|
27
|
+
You must now always pass a block to `switch`.
|
29
28
|
|
30
|
-
To
|
31
|
-
|
32
|
-
|
29
|
+
To get the previous `switch` behaviour where you can switch to a tenant
|
30
|
+
without a block, use `Apartment::Tenant.switch!`.
|
31
|
+
This is to indicate that your call actually has a side affect of changing
|
32
|
+
the scope of your queries to that tenant.
|
33
33
|
|
34
34
|
********************************
|
35
35
|
MSG
|
36
36
|
|
37
|
-
|
37
|
+
# must be >= 3.1.2 due to bug in prepared_statements
|
38
|
+
s.add_dependency 'activerecord', '>= 3.1.2', '< 5.0'
|
38
39
|
s.add_dependency 'rack', '>= 1.3.6'
|
39
40
|
|
40
41
|
s.add_development_dependency 'appraisal'
|
41
42
|
s.add_development_dependency 'rake', '~> 0.9'
|
42
43
|
s.add_development_dependency 'rspec-rails', '~> 2.14'
|
43
44
|
s.add_development_dependency 'guard-rspec', '~> 4.2'
|
44
|
-
s.add_development_dependency 'capybara', '~>
|
45
|
+
s.add_development_dependency 'capybara', '~> 2.0'
|
45
46
|
|
46
47
|
if defined?(JRUBY_VERSION)
|
47
48
|
s.add_development_dependency 'activerecord-jdbc-adapter'
|
data/lib/apartment.rb
CHANGED
@@ -3,6 +3,7 @@ require 'active_support/core_ext/object/blank'
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'active_record'
|
5
5
|
require 'apartment/tenant'
|
6
|
+
require 'apartment/deprecation'
|
6
7
|
|
7
8
|
module Apartment
|
8
9
|
|
@@ -16,7 +17,7 @@ module Apartment
|
|
16
17
|
attr_accessor(*ACCESSOR_METHODS)
|
17
18
|
attr_writer(*WRITER_METHODS)
|
18
19
|
|
19
|
-
def_delegators :connection_class, :connection, :establish_connection
|
20
|
+
def_delegators :connection_class, :connection, :connection_config, :establish_connection
|
20
21
|
|
21
22
|
# configure apartment with available options
|
22
23
|
def configure
|
@@ -42,8 +43,10 @@ module Apartment
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def default_schema
|
45
|
-
@default_schema || "public"
|
46
|
+
@default_schema || "public" # TODO 'public' is postgres specific
|
46
47
|
end
|
48
|
+
alias :default_tenant :default_schema
|
49
|
+
alias :default_tenant= :default_schema=
|
47
50
|
|
48
51
|
def persistent_schemas
|
49
52
|
@persistent_schemas || []
|
@@ -69,22 +72,22 @@ module Apartment
|
|
69
72
|
end
|
70
73
|
|
71
74
|
def database_names
|
72
|
-
warn "[Deprecation Warning] `database_names` is now deprecated, please use `tenant_names`"
|
75
|
+
Apartment::Deprecation.warn "[Deprecation Warning] `database_names` is now deprecated, please use `tenant_names`"
|
73
76
|
tenant_names
|
74
77
|
end
|
75
78
|
|
76
79
|
def database_names=(names)
|
77
|
-
warn "[Deprecation Warning] `database_names=` is now deprecated, please use `tenant_names=`"
|
80
|
+
Apartment::Deprecation.warn "[Deprecation Warning] `database_names=` is now deprecated, please use `tenant_names=`"
|
78
81
|
self.tenant_names=(names)
|
79
82
|
end
|
80
83
|
|
81
84
|
def use_postgres_schemas
|
82
|
-
warn "[Deprecation Warning] `use_postgresql_schemas` is now deprecated, please use `use_schemas`"
|
85
|
+
Apartment::Deprecation.warn "[Deprecation Warning] `use_postgresql_schemas` is now deprecated, please use `use_schemas`"
|
83
86
|
use_schemas
|
84
87
|
end
|
85
88
|
|
86
89
|
def use_postgres_schemas=(to_use_or_not_to_use)
|
87
|
-
warn "[Deprecation Warning] `use_postgresql_schemas=` is now deprecated, please use `use_schemas=`"
|
90
|
+
Apartment::Deprecation.warn "[Deprecation Warning] `use_postgresql_schemas=` is now deprecated, please use `use_schemas=`"
|
88
91
|
self.use_schemas = to_use_or_not_to_use
|
89
92
|
end
|
90
93
|
end
|
@@ -98,18 +101,6 @@ module Apartment
|
|
98
101
|
# Tenant specified is unknown
|
99
102
|
TenantNotFound = Class.new(ApartmentError)
|
100
103
|
|
101
|
-
# Raised when database cannot find the specified database
|
102
|
-
DatabaseNotFound = Class.new(TenantNotFound)
|
103
|
-
|
104
|
-
# Raised when database cannot find the specified schema
|
105
|
-
SchemaNotFound = Class.new(TenantNotFound)
|
106
|
-
|
107
104
|
# The Tenant attempting to be created already exists
|
108
105
|
TenantExists = Class.new(ApartmentError)
|
109
|
-
|
110
|
-
# Raised when trying to create a database that already exists
|
111
|
-
DatabaseExists = Class.new(TenantExists)
|
112
|
-
|
113
|
-
# Raised when trying to create a schema that already exists
|
114
|
-
SchemaExists = Class.new(TenantExists)
|
115
106
|
end
|
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'apartment/deprecation'
|
2
|
+
|
1
3
|
module Apartment
|
2
4
|
module Adapters
|
3
5
|
class AbstractAdapter
|
6
|
+
attr_writer :default_tenant
|
4
7
|
|
5
8
|
# @constructor
|
6
9
|
# @param {Hash} config Database config
|
@@ -16,7 +19,7 @@ module Apartment
|
|
16
19
|
def create(tenant)
|
17
20
|
create_tenant(tenant)
|
18
21
|
|
19
|
-
|
22
|
+
switch(tenant) do
|
20
23
|
import_database_schema
|
21
24
|
|
22
25
|
# Seed data if appropriate
|
@@ -31,8 +34,8 @@ module Apartment
|
|
31
34
|
# @return {String} current tenant name
|
32
35
|
#
|
33
36
|
def current_database
|
34
|
-
warn "[Deprecation Warning] `current_database` is now deprecated, please use `
|
35
|
-
|
37
|
+
Apartment::Deprecation.warn "[Deprecation Warning] `current_database` is now deprecated, please use `current`"
|
38
|
+
current
|
36
39
|
end
|
37
40
|
|
38
41
|
# Get the current tenant name
|
@@ -40,38 +43,81 @@ module Apartment
|
|
40
43
|
# @return {String} current tenant name
|
41
44
|
#
|
42
45
|
def current_tenant
|
43
|
-
Apartment.
|
46
|
+
Apartment::Deprecation.warn "[Deprecation Warning] `current_tenant` is now deprecated, please use `current`"
|
47
|
+
current
|
44
48
|
end
|
45
49
|
|
46
50
|
# Note alias_method here doesn't work with inheritence apparently ??
|
47
51
|
#
|
48
52
|
def current
|
49
|
-
|
53
|
+
Apartment.connection.current_database
|
50
54
|
end
|
51
55
|
|
56
|
+
# Return the original public tenant
|
57
|
+
#
|
58
|
+
# @return {String} default tenant name
|
59
|
+
#
|
60
|
+
def default_tenant
|
61
|
+
@default_tenant || Apartment.default_tenant
|
62
|
+
end
|
63
|
+
alias :default_schema :default_tenant # TODO deprecate default_schema
|
64
|
+
|
52
65
|
# Drop the tenant
|
53
66
|
#
|
54
|
-
# @param {String} tenant
|
67
|
+
# @param {String} tenant name
|
55
68
|
#
|
56
69
|
def drop(tenant)
|
57
70
|
# Apartment.connection.drop_database note that drop_database will not throw an exception, so manually execute
|
58
71
|
Apartment.connection.execute("DROP DATABASE #{environmentify(tenant)}" )
|
59
72
|
|
60
73
|
rescue *rescuable_exceptions
|
61
|
-
raise
|
74
|
+
raise TenantNotFound, "The tenant #{environmentify(tenant)} cannot be found"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Switch to a new tenant
|
78
|
+
#
|
79
|
+
# @param {String} tenant name
|
80
|
+
#
|
81
|
+
def switch!(tenant = nil)
|
82
|
+
return reset if tenant.nil?
|
83
|
+
|
84
|
+
connect_to_new(tenant).tap do
|
85
|
+
Apartment.connection.clear_query_cache
|
86
|
+
end
|
62
87
|
end
|
63
88
|
|
64
89
|
# Connect to tenant, do your biz, switch back to previous tenant
|
65
90
|
#
|
66
|
-
# @param {String?} tenant
|
91
|
+
# @param {String?} tenant to connect to
|
67
92
|
#
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
93
|
+
def switch(tenant = nil)
|
94
|
+
if block_given?
|
95
|
+
begin
|
96
|
+
previous_tenant = current
|
97
|
+
switch!(tenant)
|
98
|
+
yield
|
99
|
+
|
100
|
+
ensure
|
101
|
+
switch!(previous_tenant) rescue reset
|
102
|
+
end
|
103
|
+
else
|
104
|
+
Apartment::Deprecation.warn("[Deprecation Warning] `switch` now requires a block reset to the default tenant after the block. Please use `switch!` instead if you don't want this")
|
105
|
+
switch!(tenant)
|
106
|
+
end
|
107
|
+
end
|
72
108
|
|
73
|
-
|
74
|
-
|
109
|
+
# [Deprecated]
|
110
|
+
def process(tenant = nil, &block)
|
111
|
+
Apartment::Deprecation.warn("[Deprecation Warning] `process` is now deprecated. Please use `switch`")
|
112
|
+
switch(tenant, &block)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Iterate over all tenants, switch to tenant and yield tenant name
|
116
|
+
#
|
117
|
+
def each(tenants = Apartment.tenant_names)
|
118
|
+
tenants.each do |tenant|
|
119
|
+
switch(tenant){ yield tenant }
|
120
|
+
end
|
75
121
|
end
|
76
122
|
|
77
123
|
# Establish a new connection for each specific excluded model
|
@@ -89,19 +135,6 @@ module Apartment
|
|
89
135
|
Apartment.establish_connection @config
|
90
136
|
end
|
91
137
|
|
92
|
-
# Switch to new connection (or schema if appopriate)
|
93
|
-
#
|
94
|
-
# @param {String} tenant Database name
|
95
|
-
#
|
96
|
-
def switch(tenant = nil)
|
97
|
-
# Just connect to default db and return
|
98
|
-
return reset if tenant.nil?
|
99
|
-
|
100
|
-
connect_to_new(tenant).tap do
|
101
|
-
ActiveRecord::Base.connection.clear_query_cache
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
138
|
# Load the rails seed file into the db
|
106
139
|
#
|
107
140
|
def seed_data
|
@@ -119,7 +152,7 @@ module Apartment
|
|
119
152
|
Apartment.connection.create_database( environmentify(tenant) )
|
120
153
|
|
121
154
|
rescue *rescuable_exceptions
|
122
|
-
raise
|
155
|
+
raise TenantExists, "The tenant #{environmentify(tenant)} already exists."
|
123
156
|
end
|
124
157
|
|
125
158
|
# Connect to new tenant
|
@@ -131,7 +164,7 @@ module Apartment
|
|
131
164
|
Apartment.connection.active? # call active? to manually check if this connection is valid
|
132
165
|
|
133
166
|
rescue *rescuable_exceptions
|
134
|
-
raise
|
167
|
+
raise TenantNotFound, "The tenant #{environmentify(tenant)} cannot be found."
|
135
168
|
end
|
136
169
|
|
137
170
|
# Prepend the environment if configured and the environment isn't already there
|
@@ -182,7 +215,7 @@ module Apartment
|
|
182
215
|
# Exceptions to rescue from on db operations
|
183
216
|
#
|
184
217
|
def rescuable_exceptions
|
185
|
-
[ActiveRecord::ActiveRecordError] +
|
218
|
+
[ActiveRecord::ActiveRecordError] + Array(rescue_from)
|
186
219
|
end
|
187
220
|
|
188
221
|
# Extra exceptions to rescue from
|
@@ -21,9 +21,9 @@ module Apartment
|
|
21
21
|
#
|
22
22
|
def connect_to_new(database)
|
23
23
|
super
|
24
|
-
rescue
|
24
|
+
rescue TenantNotFound
|
25
25
|
Apartment::Tenant.reset
|
26
|
-
raise
|
26
|
+
raise TenantNotFound, "Cannot find database #{environmentify(database)}"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -23,7 +23,7 @@ module Apartment
|
|
23
23
|
Apartment.connection.create_database(environmentify(tenant), { :thisisahack => '' })
|
24
24
|
|
25
25
|
rescue *rescuable_exceptions
|
26
|
-
raise
|
26
|
+
raise TenantExists, "The tenant #{environmentify(tenant)} already exists."
|
27
27
|
end
|
28
28
|
|
29
29
|
# Return a new config that is multi-tenanted
|
@@ -50,11 +50,11 @@ module Apartment
|
|
50
50
|
return reset if tenant.nil?
|
51
51
|
raise ActiveRecord::StatementInvalid.new("Could not find schema #{tenant}") unless Apartment.connection.all_schemas.include? tenant.to_s
|
52
52
|
|
53
|
-
@
|
53
|
+
@current = tenant.to_s
|
54
54
|
Apartment.connection.schema_search_path = full_search_path
|
55
55
|
|
56
56
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::JDBCError
|
57
|
-
raise
|
57
|
+
raise TenantNotFound, "One of the following schema(s) is invalid: #{full_search_path}"
|
58
58
|
end
|
59
59
|
|
60
60
|
private
|