apartment 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|