apartment 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +5 -8
- data/Gemfile +1 -0
- data/README.md +79 -4
- data/apartment.gemspec +2 -2
- data/gemfiles/rails_3_2.gemfile +2 -0
- data/lib/apartment.rb +22 -2
- data/lib/apartment/adapters/abstract_adapter.rb +70 -16
- data/lib/apartment/adapters/abstract_jdbc_adapter.rb +4 -9
- data/lib/apartment/adapters/jdbc_mysql_adapter.rb +2 -13
- data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +5 -16
- data/lib/apartment/adapters/mysql2_adapter.rb +8 -19
- data/lib/apartment/adapters/postgresql_adapter.rb +16 -41
- data/lib/apartment/adapters/sqlite3_adapter.rb +6 -3
- data/lib/apartment/elevators/first_subdomain.rb +1 -1
- data/lib/apartment/elevators/generic.rb +5 -3
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +26 -1
- data/lib/tasks/apartment.rake +0 -1
- data/spec/adapters/jdbc_mysql_adapter_spec.rb +1 -1
- data/spec/adapters/jdbc_postgresql_adapter_spec.rb +1 -1
- data/spec/adapters/mysql2_adapter_spec.rb +2 -1
- data/spec/adapters/postgresql_adapter_spec.rb +1 -0
- data/spec/adapters/sqlite3_adapter_spec.rb +56 -0
- data/spec/apartment_spec.rb +2 -2
- data/spec/examples/connection_adapter_examples.rb +1 -1
- data/spec/examples/generic_adapter_custom_configuration_example.rb +90 -0
- data/spec/examples/generic_adapter_examples.rb +15 -15
- data/spec/examples/schema_adapter_examples.rb +25 -25
- data/spec/integration/apartment_rake_integration_spec.rb +4 -4
- data/spec/integration/query_caching_spec.rb +2 -2
- data/spec/spec_helper.rb +11 -0
- data/spec/support/apartment_helpers.rb +8 -2
- data/spec/support/setup.rb +3 -3
- data/spec/tasks/apartment_rake_spec.rb +11 -11
- data/spec/tenant_spec.rb +12 -12
- data/spec/unit/config_spec.rb +53 -23
- data/spec/unit/elevators/domain_spec.rb +4 -4
- data/spec/unit/elevators/first_subdomain_spec.rb +7 -2
- data/spec/unit/elevators/generic_spec.rb +19 -2
- data/spec/unit/elevators/host_hash_spec.rb +2 -2
- data/spec/unit/elevators/subdomain_spec.rb +6 -6
- data/spec/unit/migrator_spec.rb +1 -1
- data/spec/unit/reloader_spec.rb +2 -2
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5edda0f57e98bfa6166bb6bd4fcea9368cdc2963
|
4
|
+
data.tar.gz: 8fdda9e1bbee41a48490ae0c61dc6bc18d5084c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7450954792e78f6bd27bb8c4a6414853331562554d027cb54703746f59f1f255d898b8966349640494c7574917924ab3faa690ef07d295791d50693c56b6a0eb
|
7
|
+
data.tar.gz: 9ffd46752338eb87341c0deb314395e0f8223beb5744a2ade9a632be6234f6ec68184a1ab01744b404978e11b25f80d03314645510cda7fb8875a1f86809c86d
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.3
|
data/.travis.yml
CHANGED
@@ -1,25 +1,22 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 1.9.3
|
4
3
|
- 2.0.0
|
5
|
-
- 2.1.
|
6
|
-
- 2.2.
|
7
|
-
-
|
8
|
-
- jruby-
|
4
|
+
- 2.1.9
|
5
|
+
- 2.2.4
|
6
|
+
- 2.3.1
|
7
|
+
- jruby-9.0.5.0
|
9
8
|
gemfile:
|
10
9
|
- gemfiles/rails_3_2.gemfile
|
11
10
|
- gemfiles/rails_4_0.gemfile
|
12
11
|
- gemfiles/rails_4_1.gemfile
|
13
12
|
- gemfiles/rails_4_2.gemfile
|
14
|
-
bundler_args: --without local
|
13
|
+
bundler_args: --without local
|
15
14
|
before_install:
|
16
15
|
- gem install bundler -v '> 1.5.0'
|
17
16
|
env:
|
18
17
|
RUBY_GC_MALLOC_LIMIT: 90000000
|
19
18
|
RUBY_FREE_MIN: 200000
|
20
19
|
matrix:
|
21
|
-
allow_failures:
|
22
|
-
- rvm: jruby-head
|
23
20
|
exclude:
|
24
21
|
- rvm: 2.2.0
|
25
22
|
gemfile: gemfiles/rails_3_2.gemfile
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,14 +8,22 @@ Apartment provides tools to help you deal with multiple tenants in your Rails
|
|
8
8
|
application. If you need to have certain data sequestered based on account or company,
|
9
9
|
but still allow some data to exist in a common tenant, Apartment can help.
|
10
10
|
|
11
|
+
## HELP!
|
12
|
+
|
13
|
+
In order to help drive the direction of development and clean up the codebase, we'd like to take a poll
|
14
|
+
on how people are currently using Apartment. If you can take 5 seconds (1 question) to answer
|
15
|
+
this poll, we'd greatly appreciated it.
|
16
|
+
|
17
|
+
[View Poll](http://www.poll-maker.com/poll391552x4Bfb41a9-15)
|
18
|
+
|
11
19
|
## Excessive Memory Issues on ActiveRecord 4.x
|
12
20
|
|
13
21
|
> If you're noticing ever growing memory issues (ie growing with each tenant you add)
|
14
22
|
> when using Apartment, that's because there's [an issue](https://github.com/rails/rails/issues/19578)
|
15
23
|
> with how ActiveRecord maps Postgresql data types into AR data types.
|
16
|
-
> This has been patched and will be
|
24
|
+
> This has been patched and will be released for AR 4.2.2. It's apparently hard
|
17
25
|
> to backport to 4.1 unfortunately.
|
18
|
-
> If you
|
26
|
+
> If you're noticing high memory usage from ActiveRecord with Apartment please upgrade.
|
19
27
|
|
20
28
|
```ruby
|
21
29
|
gem 'rails', '4.2.1', github: 'influitive/rails', tag: 'v4.2.1.memfix'
|
@@ -118,7 +126,16 @@ module MyApplication
|
|
118
126
|
end
|
119
127
|
```
|
120
128
|
|
121
|
-
|
129
|
+
By default, the subdomain elevator assumes that the parent domain consists of two segments, e.g. 'example.com'. If this isn't the case, you can adjust the `tld_length` (top level domain length) configuration variable, which defaults to 1. For example, if you are using 'localhost' in development:
|
130
|
+
```ruby
|
131
|
+
# config/initializers/apartment.rb
|
132
|
+
Apartment.configure do |config|
|
133
|
+
...
|
134
|
+
config.tld_length = 0 if Rails.env == 'development'
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
If you want to exclude a domain, for example if you don't want your application to treat www like a subdomain, in an initializer in your application, you can set the following:
|
122
139
|
|
123
140
|
```ruby
|
124
141
|
# config/initializers/apartment/subdomain_exclusions.rb
|
@@ -127,6 +144,27 @@ Apartment::Elevators::Subdomain.excluded_subdomains = ['www']
|
|
127
144
|
|
128
145
|
This functions much in the same way as Apartment.excluded_models. This example will prevent switching your tenant when the subdomain is www. Handy for subdomains like: "public", "www", and "admin" :)
|
129
146
|
|
147
|
+
**Switch on first subdomain**
|
148
|
+
To switch on the first subdomain, which analyzes the chain of subdomains of the request and switches to a tenant schema of the first name in the chain (e.g. owls.birds.animals.com would switch to "owl"). It can be used like so:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
# application.rb
|
152
|
+
module MyApplication
|
153
|
+
class Application < Rails::Application
|
154
|
+
config.middleware.use 'Apartment::Elevators::FirstSubdomain'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
If you want to exclude a domain, for example if you don't want your application to treate www like a subdomain, in an initializer in your application, you can set the following:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
# config/initializers/apartment/subdomain_exclusions.rb
|
163
|
+
Apartment::Elevators::FirstSubdomain.excluded_subdomains = ['www']
|
164
|
+
```
|
165
|
+
|
166
|
+
This functions much in the same way as the Subdomain elevator.
|
167
|
+
|
130
168
|
**Switch on domain**
|
131
169
|
To switch based on full domain (excluding subdomains *ie 'www'* and top level domains *ie '.com'* ) use the following:
|
132
170
|
|
@@ -187,6 +225,16 @@ class MyCustomElevator < Apartment::Elevators::Generic
|
|
187
225
|
end
|
188
226
|
```
|
189
227
|
|
228
|
+
### Dropping Tenants
|
229
|
+
|
230
|
+
To drop tenants using Apartment, use the following command:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
Apartment::Tenant.drop('tenant_name')
|
234
|
+
```
|
235
|
+
|
236
|
+
When method is called, the schema is dropped and all data from itself will be lost. Be careful with this method.
|
237
|
+
|
190
238
|
## Config
|
191
239
|
|
192
240
|
The following config options should be set up in a Rails initializer such as:
|
@@ -225,7 +273,7 @@ By default, ActiveRecord will use `"$user", public` as the default `schema_searc
|
|
225
273
|
config.default_schema = "some_other_schema"
|
226
274
|
```
|
227
275
|
|
228
|
-
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
|
276
|
+
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.
|
229
277
|
|
230
278
|
## Persistent Schemas
|
231
279
|
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:
|
@@ -377,6 +425,33 @@ and test environments. If you wish to turn this option off in production, you c
|
|
377
425
|
config.prepend_environment = !Rails.env.production?
|
378
426
|
```
|
379
427
|
|
428
|
+
## Tenants on different servers
|
429
|
+
|
430
|
+
You can store your tenants in different databases on one or more servers.
|
431
|
+
To do it, specify your `tenant_names` as a hash, keys being the actual tenant names,
|
432
|
+
values being a hash with the database configuration to use.
|
433
|
+
|
434
|
+
Example:
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
config.tenant_names = {
|
438
|
+
'tenant1' => {
|
439
|
+
adapter: 'postgresql',
|
440
|
+
host: 'some_server',
|
441
|
+
port: 5555,
|
442
|
+
database: 'postgres' # this is not the name of the tenant's db
|
443
|
+
# but the name of the database to connect to, before creating the tenant's db
|
444
|
+
# mandatory in postgresql
|
445
|
+
}
|
446
|
+
}
|
447
|
+
# or using a lambda:
|
448
|
+
config.tenant_names = lambda do
|
449
|
+
Tenant.all.each_with_object({}) do |tenant, hash|
|
450
|
+
hash[tenant.name] = tenant.db_configuration
|
451
|
+
end
|
452
|
+
end
|
453
|
+
```
|
454
|
+
|
380
455
|
## Delayed::Job
|
381
456
|
### Has been removed... See apartment-sidekiq for a better backgrounding experience
|
382
457
|
|
data/apartment.gemspec
CHANGED
@@ -40,8 +40,8 @@ Gem::Specification.new do |s|
|
|
40
40
|
|
41
41
|
s.add_development_dependency 'appraisal'
|
42
42
|
s.add_development_dependency 'rake', '~> 0.9'
|
43
|
-
s.add_development_dependency 'rspec
|
44
|
-
s.add_development_dependency '
|
43
|
+
s.add_development_dependency 'rspec', '~> 3.4'
|
44
|
+
s.add_development_dependency 'rspec-rails', '~> 3.4'
|
45
45
|
s.add_development_dependency 'capybara', '~> 2.0'
|
46
46
|
|
47
47
|
if defined?(JRUBY_VERSION)
|
data/gemfiles/rails_3_2.gemfile
CHANGED
data/lib/apartment.rb
CHANGED
@@ -24,9 +24,16 @@ module Apartment
|
|
24
24
|
yield self if block_given?
|
25
25
|
end
|
26
26
|
|
27
|
-
# Be careful not to use `return` here so both Proc and lambda can be used without breaking
|
28
27
|
def tenant_names
|
29
|
-
|
28
|
+
extract_tenant_config.keys.map(&:to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def tenants_with_config
|
32
|
+
extract_tenant_config
|
33
|
+
end
|
34
|
+
|
35
|
+
def db_config_for(tenant)
|
36
|
+
(tenants_with_config[tenant] || connection_config).with_indifferent_access
|
30
37
|
end
|
31
38
|
|
32
39
|
# Whether or not db:migrate should also migrate tenants
|
@@ -96,6 +103,19 @@ module Apartment
|
|
96
103
|
Apartment::Deprecation.warn "[Deprecation Warning] `use_postgresql_schemas=` is now deprecated, please use `use_schemas=`"
|
97
104
|
self.use_schemas = to_use_or_not_to_use
|
98
105
|
end
|
106
|
+
|
107
|
+
def extract_tenant_config
|
108
|
+
return {} unless @tenant_names
|
109
|
+
values = @tenant_names.respond_to?(:call) ? @tenant_names.call : @tenant_names
|
110
|
+
unless values.is_a? Hash
|
111
|
+
values = values.each_with_object({}) do |tenant, hash|
|
112
|
+
hash[tenant] = connection_config
|
113
|
+
end
|
114
|
+
end
|
115
|
+
values.with_indifferent_access
|
116
|
+
rescue ActiveRecord::StatementInvalid
|
117
|
+
{}
|
118
|
+
end
|
99
119
|
end
|
100
120
|
|
101
121
|
# Exceptions
|
@@ -67,11 +67,12 @@ module Apartment
|
|
67
67
|
# @param {String} tenant name
|
68
68
|
#
|
69
69
|
def drop(tenant)
|
70
|
-
|
71
|
-
|
70
|
+
with_neutral_connection(tenant) do |conn|
|
71
|
+
drop_command(conn, tenant)
|
72
|
+
end
|
72
73
|
|
73
|
-
rescue *rescuable_exceptions
|
74
|
-
|
74
|
+
rescue *rescuable_exceptions => exception
|
75
|
+
raise_drop_tenant_error!(tenant, exception)
|
75
76
|
end
|
76
77
|
|
77
78
|
# Switch to a new tenant
|
@@ -125,7 +126,7 @@ module Apartment
|
|
125
126
|
def process_excluded_models
|
126
127
|
# All other models will shared a connection (at Apartment.connection_class) and we can modify at will
|
127
128
|
Apartment.excluded_models.each do |excluded_model|
|
128
|
-
excluded_model
|
129
|
+
process_excluded_model(excluded_model)
|
129
130
|
end
|
130
131
|
end
|
131
132
|
|
@@ -139,21 +140,38 @@ module Apartment
|
|
139
140
|
#
|
140
141
|
def seed_data
|
141
142
|
# Don't log the output of seeding the db
|
142
|
-
|
143
|
+
silence_warnings{ load_or_abort(Apartment.seed_data_file) } if Apartment.seed_data_file
|
143
144
|
end
|
144
145
|
alias_method :seed, :seed_data
|
145
146
|
|
146
147
|
protected
|
147
148
|
|
149
|
+
def process_excluded_model(excluded_model)
|
150
|
+
excluded_model.constantize.establish_connection @config
|
151
|
+
end
|
152
|
+
|
153
|
+
def drop_command(conn, tenant)
|
154
|
+
# connection.drop_database note that drop_database will not throw an exception, so manually execute
|
155
|
+
conn.execute("DROP DATABASE #{environmentify(tenant)}")
|
156
|
+
end
|
157
|
+
|
158
|
+
class SeparateDbConnectionHandler < ::ActiveRecord::Base
|
159
|
+
end
|
160
|
+
|
148
161
|
# Create the tenant
|
149
162
|
#
|
150
163
|
# @param {String} tenant Database name
|
151
164
|
#
|
152
165
|
def create_tenant(tenant)
|
153
|
-
|
166
|
+
with_neutral_connection(tenant) do |conn|
|
167
|
+
create_tenant_command(conn, tenant)
|
168
|
+
end
|
169
|
+
rescue *rescuable_exceptions => exception
|
170
|
+
raise_create_tenant_error!(tenant, exception)
|
171
|
+
end
|
154
172
|
|
155
|
-
|
156
|
-
|
173
|
+
def create_tenant_command(conn, tenant)
|
174
|
+
conn.create_database(environmentify(tenant))
|
157
175
|
end
|
158
176
|
|
159
177
|
# Connect to new tenant
|
@@ -163,9 +181,9 @@ module Apartment
|
|
163
181
|
def connect_to_new(tenant)
|
164
182
|
Apartment.establish_connection multi_tenantify(tenant)
|
165
183
|
Apartment.connection.active? # call active? to manually check if this connection is valid
|
166
|
-
|
167
|
-
|
168
|
-
|
184
|
+
rescue *rescuable_exceptions => exception
|
185
|
+
Apartment::Tenant.reset if reset_on_connection_exception?
|
186
|
+
raise_connect_error!(tenant, exception)
|
169
187
|
end
|
170
188
|
|
171
189
|
# Prepend the environment if configured and the environment isn't already there
|
@@ -196,13 +214,21 @@ module Apartment
|
|
196
214
|
end
|
197
215
|
|
198
216
|
# Return a new config that is multi-tenanted
|
199
|
-
#
|
200
|
-
|
201
|
-
|
202
|
-
|
217
|
+
# @param {String} tenant: Database name
|
218
|
+
# @param {Boolean} with_database: if true, use the actual tenant's db name
|
219
|
+
# if false, use the default db name from the db
|
220
|
+
def multi_tenantify(tenant, with_database = true)
|
221
|
+
db_connection_config(tenant).tap do |config|
|
222
|
+
if with_database
|
223
|
+
multi_tenantify_with_tenant_db_name(config, tenant)
|
224
|
+
end
|
203
225
|
end
|
204
226
|
end
|
205
227
|
|
228
|
+
def multi_tenantify_with_tenant_db_name(config, tenant)
|
229
|
+
config[:database] = environmentify(tenant)
|
230
|
+
end
|
231
|
+
|
206
232
|
# Load a file or abort if it doesn't exists
|
207
233
|
#
|
208
234
|
def load_or_abort(file)
|
@@ -224,6 +250,34 @@ module Apartment
|
|
224
250
|
def rescue_from
|
225
251
|
[]
|
226
252
|
end
|
253
|
+
|
254
|
+
def db_connection_config(tenant)
|
255
|
+
Apartment.db_config_for(tenant).clone
|
256
|
+
end
|
257
|
+
|
258
|
+
# neutral connection is necessary whenever you need to create/remove a database from a server.
|
259
|
+
# example: when you use postgresql, you need to connect to the default postgresql database before you create your own.
|
260
|
+
def with_neutral_connection(tenant, &block)
|
261
|
+
SeparateDbConnectionHandler.establish_connection(multi_tenantify(tenant, false))
|
262
|
+
yield(SeparateDbConnectionHandler.connection)
|
263
|
+
SeparateDbConnectionHandler.connection.close
|
264
|
+
end
|
265
|
+
|
266
|
+
def reset_on_connection_exception?
|
267
|
+
false
|
268
|
+
end
|
269
|
+
|
270
|
+
def raise_drop_tenant_error!(tenant, exception)
|
271
|
+
raise TenantNotFound, "Error while dropping tenant #{environmentify(tenant)}: #{ exception.message }"
|
272
|
+
end
|
273
|
+
|
274
|
+
def raise_create_tenant_error!(tenant, exception)
|
275
|
+
raise TenantExists, "Error while creating tenant #{environmentify(tenant)}: #{ exception.message }"
|
276
|
+
end
|
277
|
+
|
278
|
+
def raise_connect_error!(tenant, exception)
|
279
|
+
raise TenantNotFound, "Error while connecting to tenant #{environmentify(tenant)}: #{ exception.message }"
|
280
|
+
end
|
227
281
|
end
|
228
282
|
end
|
229
283
|
end
|
@@ -4,20 +4,15 @@ module Apartment
|
|
4
4
|
module Adapters
|
5
5
|
class AbstractJDBCAdapter < AbstractAdapter
|
6
6
|
|
7
|
-
|
7
|
+
private
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
def multi_tenantify(database)
|
12
|
-
@config.clone.tap do |config|
|
13
|
-
config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(database)}"
|
14
|
-
end
|
9
|
+
def multi_tenantify_with_tenant_db_name(config, tenant)
|
10
|
+
config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(tenant)}"
|
15
11
|
end
|
16
|
-
private
|
17
12
|
|
18
13
|
def rescue_from
|
19
14
|
ActiveRecord::JDBCError
|
20
15
|
end
|
21
16
|
end
|
22
17
|
end
|
23
|
-
end
|
18
|
+
end
|
@@ -11,19 +11,8 @@ module Apartment
|
|
11
11
|
module Adapters
|
12
12
|
class JDBCMysqlAdapter < AbstractJDBCAdapter
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
# Connect to new database
|
17
|
-
# Abstract adapter will catch generic ActiveRecord error
|
18
|
-
# Catch specific adapter errors here
|
19
|
-
#
|
20
|
-
# @param {String} database Database name
|
21
|
-
#
|
22
|
-
def connect_to_new(database)
|
23
|
-
super
|
24
|
-
rescue TenantNotFound
|
25
|
-
Apartment::Tenant.reset
|
26
|
-
raise TenantNotFound, "Cannot find database #{environmentify(database)}"
|
14
|
+
def reset_on_connection_exception?
|
15
|
+
true
|
27
16
|
end
|
28
17
|
end
|
29
18
|
end
|
@@ -15,27 +15,16 @@ module Apartment
|
|
15
15
|
# Default adapter when not using Postgresql Schemas
|
16
16
|
class JDBCPostgresqlAdapter < PostgresqlAdapter
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
def create_tenant(tenant)
|
21
|
-
# There is a bug in activerecord-jdbcpostgresql-adapter (1.2.5) that will cause
|
22
|
-
# an exception if no options are passed into the create_database call.
|
23
|
-
Apartment.connection.create_database(environmentify(tenant), { :thisisahack => '' })
|
18
|
+
private
|
24
19
|
|
25
|
-
|
26
|
-
|
20
|
+
def multi_tenantify_with_tenant_db_name(config, tenant)
|
21
|
+
config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(tenant)}"
|
27
22
|
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
def multi_tenantify(tenant)
|
32
|
-
@config.clone.tap do |config|
|
33
|
-
config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(tenant)}"
|
34
|
-
end
|
24
|
+
def create_tenant_command(conn, tenant)
|
25
|
+
conn.create_database(environmentify(tenant), { :thisisahack => '' })
|
35
26
|
end
|
36
27
|
|
37
|
-
private
|
38
|
-
|
39
28
|
def rescue_from
|
40
29
|
ActiveRecord::JDBCError
|
41
30
|
end
|