apartment 0.23.2 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/HISTORY.md +12 -1
- data/README.md +16 -13
- data/Rakefile +6 -1
- data/TODO.md +9 -14
- data/lib/apartment.rb +17 -3
- data/lib/apartment/adapters/abstract_adapter.rb +53 -44
- data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +9 -9
- data/lib/apartment/adapters/mysql2_adapter.rb +15 -15
- data/lib/apartment/adapters/postgresql_adapter.rb +26 -18
- data/lib/apartment/adapters/sqlite3_adapter.rb +13 -13
- data/lib/apartment/database.rb +2 -2
- data/lib/apartment/elevators/host_hash.rb +3 -3
- data/lib/apartment/elevators/subdomain.rb +2 -3
- data/lib/apartment/migrator.rb +3 -3
- data/lib/apartment/railtie.rb +2 -1
- data/lib/apartment/tasks/enhancements.rb +26 -0
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +13 -8
- data/lib/tasks/apartment.rake +34 -38
- data/spec/adapters/jdbc_mysql_adapter_spec.rb +2 -4
- data/spec/adapters/jdbc_postgresql_adapter_spec.rb +6 -6
- data/spec/adapters/mysql2_adapter_spec.rb +5 -5
- data/spec/adapters/postgresql_adapter_spec.rb +6 -6
- data/spec/adapters/sqlite3_adapter_spec.rb +2 -2
- data/spec/database_spec.rb +2 -2
- data/spec/dummy/config/initializers/apartment.rb +2 -2
- data/spec/examples/connection_adapter_examples.rb +2 -2
- data/spec/examples/generic_adapter_examples.rb +15 -15
- data/spec/examples/schema_adapter_examples.rb +6 -6
- data/spec/integration/apartment_rake_integration_spec.rb +4 -4
- data/spec/integration/query_caching_spec.rb +2 -2
- data/spec/support/requirements.rb +2 -5
- data/spec/tasks/apartment_rake_spec.rb +8 -9
- data/spec/unit/config_spec.rb +17 -10
- data/spec/unit/elevators/subdomain_spec.rb +26 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc20eef867490ea70d61bd13cf152a659cfb0fa4
|
4
|
+
data.tar.gz: b1110bf18327723c487d0cb1efe82f85a7d7bfc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc1d19df9b94a6703c1d2a88b93c628bdb809ae729e104afa8550e51dfed3da2dd958292936f971e5c22e07e58d6a032e9f0300a2a1a65856e9986e8d2d44937
|
7
|
+
data.tar.gz: 3bd127557fdd6743d6886ebf3ea4c720a5ebd6deff4623f519078bef5cf55e9db2f528e13458bb38cecde6d36762a1178ec2fa3e61c111b05cc74f3614e27ebb
|
data/HISTORY.md
CHANGED
@@ -1,4 +1,15 @@
|
|
1
|
-
# 0
|
1
|
+
# 0.24
|
2
|
+
* February 21, 2014 (In honour of the Women's Gold Medal in Hockey at Sochi)
|
3
|
+
|
4
|
+
- [BREAKING CHANGE] `apartment:migrate` task no longer depends on `db:migrate`
|
5
|
+
- Instead, you can `require 'apartment/tasks/enhancements'` in your Apartment initializer
|
6
|
+
- This will enhance `rake db:migrate` to also run `apartment:migrate`
|
7
|
+
- You can now forget about ever running `apartment:migrate` again
|
8
|
+
- Numerous deprecations for things referencing the word 'database'
|
9
|
+
- This is an ongoing effort to completely replace 'database' with 'tenant' as a better abstraction
|
10
|
+
- Note the obvious `Apartment::Database` still exists but will hopefully become `Apartment::Tenant` soon
|
11
|
+
|
12
|
+
# 0.23.2
|
2
13
|
* January 9, 2014
|
3
14
|
|
4
15
|
- Increased visibility of #parse_database_name warning
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
[![Code Climate](https://codeclimate.com/github/influitive/apartment.png)](https://codeclimate.com/github/influitive/apartment)
|
3
3
|
[![Build Status](https://secure.travis-ci.org/influitive/apartment.png?branch=development)](http://travis-ci.org/influitive/apartment)
|
4
4
|
|
5
|
-
*Multitenancy for Rails
|
5
|
+
*Multitenancy for Rails and ActiveRecord*
|
6
6
|
|
7
7
|
Apartment provides tools to help you deal with multiple databases in your Rails
|
8
8
|
application. If you need to have certain data sequestered based on account or company,
|
@@ -11,7 +11,7 @@ but still allow some data to exist in a common database, Apartment can help.
|
|
11
11
|
|
12
12
|
## Installation
|
13
13
|
|
14
|
-
### Rails
|
14
|
+
### Rails
|
15
15
|
|
16
16
|
Add the following to your Gemfile:
|
17
17
|
|
@@ -164,7 +164,7 @@ end
|
|
164
164
|
|
165
165
|
### Excluding models
|
166
166
|
|
167
|
-
If you have some models that should always access the '
|
167
|
+
If you have some models that should always access the 'public' database, 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:
|
168
168
|
|
169
169
|
```ruby
|
170
170
|
config.excluded_models = ["User", "Company"] # these models will not be multi-tenanted, but remain in the global (public) namespace
|
@@ -172,7 +172,10 @@ config.excluded_models = ["User", "Company"] # these models will not be m
|
|
172
172
|
|
173
173
|
Note that a string representation of the model name is now the standard so that models are properly constantized when reloaded in development
|
174
174
|
|
175
|
-
Rails will always access the '
|
175
|
+
Rails will always access the 'public' database when accessing these models, but note that tables will be created in all schemas. This may not be ideal, but its done this way because otherwise rails wouldn't be able to properly generate the schema.rb file.
|
176
|
+
|
177
|
+
> **NOTE - Many-To-Many Excluded Models:**
|
178
|
+
> Since model exclusions must come from referencing a real ActiveRecord model, `has_and_belongs_to_many` is NOT supported. In order to achieve a many-to-many relationship for excluded models, you MUST use `has_many :through`. This way you can reference the join model in the excluded models configuration.
|
176
179
|
|
177
180
|
### Postgresql Schemas
|
178
181
|
|
@@ -221,7 +224,7 @@ schema_search_path: "public,hstore"
|
|
221
224
|
This would be for a config with `default_schema` set to `public` and `persistent_schemas` set to `['hstore']`
|
222
225
|
|
223
226
|
Another way that we've successfully configured hstore for our applications is to add it into the
|
224
|
-
postgresql template1 database so that every
|
227
|
+
postgresql template1 database so that every tenant that gets created has it by default.
|
225
228
|
|
226
229
|
You can do so using a command like so
|
227
230
|
|
@@ -239,26 +242,26 @@ Happy to accept PR's on the matter.
|
|
239
242
|
|
240
243
|
In order to migrate all of your databases (or posgresql schemas) you need to provide a list
|
241
244
|
of dbs to Apartment. You can make this dynamic by providing a Proc object to be called on migrations.
|
242
|
-
This object should yield an array of string representing each
|
245
|
+
This object should yield an array of string representing each tenant name. Example:
|
243
246
|
|
244
247
|
```ruby
|
245
|
-
# Dynamically get
|
246
|
-
config.
|
248
|
+
# Dynamically get tenant names to migrate
|
249
|
+
config.tenant_names = lambda{ Customer.pluck(:tenant_name) }
|
247
250
|
|
248
|
-
# Use a static list of
|
249
|
-
config.
|
251
|
+
# Use a static list of tenant names for migrate
|
252
|
+
config.tenant_names = ['tenant1', 'tenant2']
|
250
253
|
```
|
251
254
|
|
252
255
|
You can then migrate your databases using the rake task:
|
253
256
|
|
254
257
|
rake apartment:migrate
|
255
258
|
|
256
|
-
This basically invokes `Apartment::Database.migrate(#{
|
257
|
-
from `Apartment.
|
259
|
+
This basically invokes `Apartment::Database.migrate(#{tenant_name})` for each tenant name supplied
|
260
|
+
from `Apartment.tenant_names`
|
258
261
|
|
259
262
|
### Handling Environments
|
260
263
|
|
261
|
-
By default, when not using postgresql schemas, Apartment will prepend the environment to the
|
264
|
+
By default, when not using postgresql schemas, Apartment will prepend the environment to the tenant name
|
262
265
|
to ensure there is no conflict between your environments. This is mainly for the benefit of your development
|
263
266
|
and test environments. If you wish to turn this option off in production, you could do something like:
|
264
267
|
|
data/Rakefile
CHANGED
@@ -13,13 +13,18 @@ RSpec::Core::RakeTask.new(:spec => %w{ db:copy_credentials db:test:prepare }) do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
namespace :spec do
|
16
|
-
|
17
16
|
[:tasks, :unit, :adapters, :integration].each do |type|
|
18
17
|
RSpec::Core::RakeTask.new(type => :spec) do |spec|
|
19
18
|
spec.pattern = "spec/#{type}/**/*_spec.rb"
|
20
19
|
end
|
21
20
|
end
|
21
|
+
end
|
22
22
|
|
23
|
+
task :console do
|
24
|
+
require 'pry'
|
25
|
+
require 'apartment'
|
26
|
+
ARGV.clear
|
27
|
+
Pry.start
|
23
28
|
end
|
24
29
|
|
25
30
|
task :default => :spec
|
data/TODO.md
CHANGED
@@ -15,8 +15,7 @@
|
|
15
15
|
It would be nice if a user can 'register' an adapter such that it would automatically be tested (nice to have). Otherwise one could just use
|
16
16
|
a shared behaviour to run through all of this.
|
17
17
|
|
18
|
-
Then, I'd like to see all of the implementation specific tests just in their own test file for each adapter (ie the postgresql schema adapter
|
19
|
-
checks a lot of things with `schema_search_path`)
|
18
|
+
Then, I'd like to see all of the implementation specific tests just in their own test file for each adapter (ie the postgresql schema adapter checks a lot of things with `schema_search_path`)
|
20
19
|
|
21
20
|
This should ensure that going forward nothing breaks, and we should *ideally* be able to randomize the test order
|
22
21
|
|
@@ -24,24 +23,20 @@
|
|
24
23
|
think about Tenants. I proprose that we deprecate the `Apartment::Database` constant in favour of `Apartment::Tenant` for a nicer abstraction. See
|
25
24
|
http://myronmars.to/n/dev-blog/2011/09/deprecating-constants-and-classes-in-ruby for ideas on how to achieve this.
|
26
25
|
|
27
|
-
4. Apartment::Database.process should be deprecated in favour of just passing
|
26
|
+
4. Apartment::Database.process should be deprecated in favour of just passing a block to `switch`
|
27
|
+
5. Apartment::Database.switch should be renamed to switch! to indicate that using it on its own has side effects
|
28
28
|
|
29
|
-
|
29
|
+
6. Migrations right now can be a bit of a pain. Apartment currently migrates a single tenant completely up to date, then goes onto the next. If one of these
|
30
30
|
migrations fails on a tenant, the previous one does NOT get reverted and leaves you in an awkward state. Ideally we'd want to wrap all of the migrations in
|
31
31
|
a transaction so if one fails, the whole thing reverts. Once we can ensure an all-or-nothing approach to migrations, we can optimize the migration strategy
|
32
|
-
to not even iterate over the tenants if there are no migrations to run on public.
|
33
|
-
Rakefile such that it would override `db:migrate` to do `apartment:migrate`. That way people don't have to remember to use a different task and there's no confusion.
|
32
|
+
to not even iterate over the tenants if there are no migrations to run on public.
|
34
33
|
|
35
|
-
|
36
|
-
in implementation to either schema based (ie postgresql schemas) or connection based. I'd like to abstract out these implementation details such that one
|
37
|
-
could write a pluggable strategy for Apartment and choose it based on a config selection (something like `config.strategy = :schema`). The next implementation
|
38
|
-
I'd like to see is a scoped based approach that uses a `tenant_id` scoping on all records for multi-tenancy. This is probably the most popular multi-tenant approach
|
39
|
-
and is db independent and really the simplest mechanism for a type of multi-tenancy.
|
34
|
+
7. Apartment has be come one of the most popular/robust Multi-tenant gems for Rails, but it still doesn't work for everyone's use case. It's fairly limited in implementation to either schema based (ie postgresql schemas) or connection based. I'd like to abstract out these implementation details such that one could write a pluggable strategy for Apartment and choose it based on a config selection (something like `config.strategy = :schema`). The next implementation I'd like to see is a scoped based approach that uses a `tenant_id` scoping on all records for multi-tenancy. This is probably the most popular multi-tenant approach and is db independent and really the simplest mechanism for a type of multi-tenancy.
|
40
35
|
|
41
|
-
|
36
|
+
8. Right now excluded tables still live in all tenanted environments. This is basically because it doesn't matter if they're there, we always query from the public.
|
42
37
|
It's a bit of an annoyance though and confuses lots of people. I'd love to see only tenanted tables in the tenants and only excluded tables in the public tenant.
|
43
38
|
This will be hard because Rails uses public to generate schema.rb. One idea is to have an `excluded` schema that holds all the excluded models and the public can
|
44
39
|
maintain everything.
|
45
40
|
|
46
|
-
|
47
|
-
DBMS's (ie. mongo, couch etc...), it'd be nice if Apartment could be the de-facto interface for multi-tenancy on these systems.
|
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
|
+
DBMS's (ie. mongo, couch etc...), it'd be nice if Apartment could be the de-facto interface for multi-tenancy on these systems.
|
data/lib/apartment.rb
CHANGED
@@ -11,7 +11,7 @@ module Apartment
|
|
11
11
|
extend Forwardable
|
12
12
|
|
13
13
|
ACCESSOR_METHODS = [:use_schemas, :seed_after_create, :prepend_environment, :append_environment]
|
14
|
-
WRITER_METHODS = [:
|
14
|
+
WRITER_METHODS = [:tenant_names, :database_schema_file, :excluded_models, :default_schema, :persistent_schemas, :connection_class, :tld_length]
|
15
15
|
|
16
16
|
attr_accessor(*ACCESSOR_METHODS)
|
17
17
|
attr_writer(*WRITER_METHODS)
|
@@ -24,8 +24,8 @@ module Apartment
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Be careful not to use `return` here so both Proc and lambda can be used without breaking
|
27
|
-
def
|
28
|
-
@
|
27
|
+
def tenant_names
|
28
|
+
@tenant_names.respond_to?(:call) ? @tenant_names.call : @tenant_names
|
29
29
|
end
|
30
30
|
|
31
31
|
# Default to empty array
|
@@ -51,11 +51,25 @@ module Apartment
|
|
51
51
|
@database_schema_file = Rails.root.join('db', 'schema.rb')
|
52
52
|
end
|
53
53
|
|
54
|
+
def tld_length
|
55
|
+
@tld_length || 1
|
56
|
+
end
|
57
|
+
|
54
58
|
# Reset all the config for Apartment
|
55
59
|
def reset
|
56
60
|
(ACCESSOR_METHODS + WRITER_METHODS).each{|method| remove_instance_variable(:"@#{method}") if instance_variable_defined?(:"@#{method}") }
|
57
61
|
end
|
58
62
|
|
63
|
+
def database_names
|
64
|
+
warn "[Deprecation Warning] `database_names` is now deprecated, please use `tenant_names`"
|
65
|
+
tenant_names
|
66
|
+
end
|
67
|
+
|
68
|
+
def database_names=(names)
|
69
|
+
warn "[Deprecation Warning] `database_names=` is now deprecated, please use `tenant_names=`"
|
70
|
+
self.tenant_names=(names)
|
71
|
+
end
|
72
|
+
|
59
73
|
def use_postgres_schemas
|
60
74
|
warn "[Deprecation Warning] `use_postgresql_schemas` is now deprecated, please use `use_schemas`"
|
61
75
|
use_schemas
|
@@ -9,14 +9,14 @@ module Apartment
|
|
9
9
|
@config = config
|
10
10
|
end
|
11
11
|
|
12
|
-
# Create a new
|
12
|
+
# Create a new tenant, import schema, seed if appropriate
|
13
13
|
#
|
14
|
-
# @param {String}
|
14
|
+
# @param {String} tenant Tenant name
|
15
15
|
#
|
16
|
-
def create(
|
17
|
-
create_tenant(
|
16
|
+
def create(tenant)
|
17
|
+
create_tenant(tenant)
|
18
18
|
|
19
|
-
process(
|
19
|
+
process(tenant) do
|
20
20
|
import_database_schema
|
21
21
|
|
22
22
|
# Seed data if appropriate
|
@@ -26,43 +26,52 @@ module Apartment
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
# Get the current
|
29
|
+
# Get the current tenant name
|
30
30
|
#
|
31
|
-
# @return {String} current
|
31
|
+
# @return {String} current tenant name
|
32
32
|
#
|
33
33
|
def current_database
|
34
|
+
warn "[Deprecation Warning] `current_database` is now deprecated, please use `current_tenant`"
|
35
|
+
current_tenant
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get the current tenant name
|
39
|
+
#
|
40
|
+
# @return {String} current tenant name
|
41
|
+
#
|
42
|
+
def current_tenant
|
34
43
|
Apartment.connection.current_database
|
35
44
|
end
|
36
45
|
|
37
46
|
# Note alias_method here doesn't work with inheritence apparently ??
|
38
47
|
#
|
39
48
|
def current
|
40
|
-
|
49
|
+
current_tenant
|
41
50
|
end
|
42
51
|
|
43
|
-
# Drop the
|
52
|
+
# Drop the tenant
|
44
53
|
#
|
45
|
-
# @param {String}
|
54
|
+
# @param {String} tenant Database name
|
46
55
|
#
|
47
|
-
def drop(
|
56
|
+
def drop(tenant)
|
48
57
|
# Apartment.connection.drop_database note that drop_database will not throw an exception, so manually execute
|
49
|
-
Apartment.connection.execute("DROP DATABASE #{environmentify(
|
58
|
+
Apartment.connection.execute("DROP DATABASE #{environmentify(tenant)}" )
|
50
59
|
|
51
60
|
rescue *rescuable_exceptions
|
52
|
-
raise DatabaseNotFound, "The
|
61
|
+
raise DatabaseNotFound, "The tenant #{environmentify(tenant)} cannot be found"
|
53
62
|
end
|
54
63
|
|
55
|
-
# Connect to
|
64
|
+
# Connect to tenant, do your biz, switch back to previous tenant
|
56
65
|
#
|
57
|
-
# @param {String?}
|
66
|
+
# @param {String?} tenant Database or schema to connect to
|
58
67
|
#
|
59
|
-
def process(
|
60
|
-
|
61
|
-
switch(
|
68
|
+
def process(tenant = nil)
|
69
|
+
previous_tenant = current_tenant
|
70
|
+
switch(tenant)
|
62
71
|
yield if block_given?
|
63
72
|
|
64
73
|
ensure
|
65
|
-
switch(
|
74
|
+
switch(previous_tenant) rescue reset
|
66
75
|
end
|
67
76
|
|
68
77
|
# Establish a new connection for each specific excluded model
|
@@ -74,7 +83,7 @@ module Apartment
|
|
74
83
|
end
|
75
84
|
end
|
76
85
|
|
77
|
-
# Reset the
|
86
|
+
# Reset the tenant connection to the default
|
78
87
|
#
|
79
88
|
def reset
|
80
89
|
Apartment.establish_connection @config
|
@@ -82,13 +91,13 @@ module Apartment
|
|
82
91
|
|
83
92
|
# Switch to new connection (or schema if appopriate)
|
84
93
|
#
|
85
|
-
# @param {String}
|
94
|
+
# @param {String} tenant Database name
|
86
95
|
#
|
87
|
-
def switch(
|
96
|
+
def switch(tenant = nil)
|
88
97
|
# Just connect to default db and return
|
89
|
-
return reset if
|
98
|
+
return reset if tenant.nil?
|
90
99
|
|
91
|
-
connect_to_new(
|
100
|
+
connect_to_new(tenant).tap do
|
92
101
|
ActiveRecord::Base.connection.clear_query_cache
|
93
102
|
end
|
94
103
|
end
|
@@ -102,45 +111,45 @@ module Apartment
|
|
102
111
|
|
103
112
|
protected
|
104
113
|
|
105
|
-
# Create the
|
114
|
+
# Create the tenant
|
106
115
|
#
|
107
|
-
# @param {String}
|
116
|
+
# @param {String} tenant Database name
|
108
117
|
#
|
109
|
-
def create_tenant(
|
110
|
-
Apartment.connection.create_database( environmentify(
|
118
|
+
def create_tenant(tenant)
|
119
|
+
Apartment.connection.create_database( environmentify(tenant) )
|
111
120
|
|
112
121
|
rescue *rescuable_exceptions
|
113
|
-
raise DatabaseExists, "The
|
122
|
+
raise DatabaseExists, "The tenant #{environmentify(tenant)} already exists."
|
114
123
|
end
|
115
124
|
|
116
|
-
# Connect to new
|
125
|
+
# Connect to new tenant
|
117
126
|
#
|
118
|
-
# @param {String}
|
127
|
+
# @param {String} tenant Database name
|
119
128
|
#
|
120
|
-
def connect_to_new(
|
121
|
-
Apartment.establish_connection multi_tenantify(
|
129
|
+
def connect_to_new(tenant)
|
130
|
+
Apartment.establish_connection multi_tenantify(tenant)
|
122
131
|
Apartment.connection.active? # call active? to manually check if this connection is valid
|
123
132
|
|
124
133
|
rescue *rescuable_exceptions
|
125
|
-
raise DatabaseNotFound, "The
|
134
|
+
raise DatabaseNotFound, "The tenant #{environmentify(tenant)} cannot be found."
|
126
135
|
end
|
127
136
|
|
128
137
|
# Prepend the environment if configured and the environment isn't already there
|
129
138
|
#
|
130
|
-
# @param {String}
|
131
|
-
# @return {String}
|
139
|
+
# @param {String} tenant Database name
|
140
|
+
# @return {String} tenant name with Rails environment *optionally* prepended
|
132
141
|
#
|
133
|
-
def environmentify(
|
134
|
-
unless
|
142
|
+
def environmentify(tenant)
|
143
|
+
unless tenant.include?(Rails.env)
|
135
144
|
if Apartment.prepend_environment
|
136
|
-
"#{Rails.env}_#{
|
145
|
+
"#{Rails.env}_#{tenant}"
|
137
146
|
elsif Apartment.append_environment
|
138
|
-
"#{
|
147
|
+
"#{tenant}_#{Rails.env}"
|
139
148
|
else
|
140
|
-
|
149
|
+
tenant
|
141
150
|
end
|
142
151
|
else
|
143
|
-
|
152
|
+
tenant
|
144
153
|
end
|
145
154
|
end
|
146
155
|
|
@@ -154,9 +163,9 @@ module Apartment
|
|
154
163
|
|
155
164
|
# Return a new config that is multi-tenanted
|
156
165
|
#
|
157
|
-
def multi_tenantify(
|
166
|
+
def multi_tenantify(tenant)
|
158
167
|
@config.clone.tap do |config|
|
159
|
-
config[:database] = environmentify(
|
168
|
+
config[:database] = environmentify(tenant)
|
160
169
|
end
|
161
170
|
end
|
162
171
|
|
@@ -17,20 +17,20 @@ module Apartment
|
|
17
17
|
|
18
18
|
protected
|
19
19
|
|
20
|
-
def create_tenant(
|
20
|
+
def create_tenant(tenant)
|
21
21
|
# There is a bug in activerecord-jdbcpostgresql-adapter (1.2.5) that will cause
|
22
22
|
# an exception if no options are passed into the create_database call.
|
23
|
-
Apartment.connection.create_database(environmentify(
|
23
|
+
Apartment.connection.create_database(environmentify(tenant), { :thisisahack => '' })
|
24
24
|
|
25
25
|
rescue *rescuable_exceptions
|
26
|
-
raise DatabaseExists, "The
|
26
|
+
raise DatabaseExists, "The tenant #{environmentify(tenant)} already exists."
|
27
27
|
end
|
28
28
|
|
29
29
|
# Return a new config that is multi-tenanted
|
30
30
|
#
|
31
|
-
def multi_tenantify(
|
31
|
+
def multi_tenantify(tenant)
|
32
32
|
@config.clone.tap do |config|
|
33
|
-
config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(
|
33
|
+
config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(tenant)}"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -46,11 +46,11 @@ module Apartment
|
|
46
46
|
|
47
47
|
# Set schema search path to new schema
|
48
48
|
#
|
49
|
-
def connect_to_new(
|
50
|
-
return reset if
|
51
|
-
raise ActiveRecord::StatementInvalid.new("Could not find schema #{
|
49
|
+
def connect_to_new(tenant = nil)
|
50
|
+
return reset if tenant.nil?
|
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 = tenant.to_s
|
54
54
|
Apartment.connection.schema_search_path = full_search_path
|
55
55
|
|
56
56
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::JDBCError
|