motel-activerecord 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +30 -47
- data/VERSION +1 -1
- data/lib/motel-activerecord.rb +0 -1
- data/lib/motel/active_record.rb +0 -2
- data/lib/motel/active_record/connection_handler.rb +10 -4
- data/lib/motel/active_record/railties/databases.rake +38 -0
- data/lib/motel/manager.rb +9 -22
- data/lib/motel/railtie.rb +8 -15
- data/spec/lib/motel/active_record/connection_handler.rb +51 -22
- data/spec/lib/motel/manager_spec.rb +11 -16
- data/spec/tmp/tenants.sqlite3 +0 -0
- metadata +3 -7
- data/lib/motel/active_record/migration.rb +0 -36
- data/lib/motel/active_record/query_cache.rb +0 -73
- data/lib/motel/lobby.rb +0 -39
- data/spec/lib/motel/lobby_spec.rb +0 -133
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbdd40d34d7c12ab8b85ebf22ad4c05fb9d68ec7
|
4
|
+
data.tar.gz: 42ff7e4c146a83c443e70fadc69201ddb5c756d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd1193af26b506bc7734695b2716a9bc4f448546dd4ffd49b89d471603687765d5797b102f22f4001cc83ee9e5a82a193e97f90f2cffddad2495305cb240a163
|
7
|
+
data.tar.gz: e35b6efaee61dc09687d5cdb3e3fe29361ea773076f5f97f5b8b5183a89db497c440b8bfc74c76948fc0a59d5d7a9d833d6f429d9ce2ae060e0c885d696796b7
|
data/README.md
CHANGED
@@ -8,6 +8,7 @@ connections to multiple databases, one for each tenant.
|
|
8
8
|
|
9
9
|
* Adds multi-tenant functionality to ActiveRecord.
|
10
10
|
* Multiple databases, one for each tenant.
|
11
|
+
* Databases of tenants may be in different locations.
|
11
12
|
* Tenant connection details are stored keying them by the name on a database or redis server.
|
12
13
|
* Use with or without Rails.
|
13
14
|
|
@@ -126,29 +127,21 @@ specific tenant.
|
|
126
127
|
$ TENANT=foo rake db:migrate
|
127
128
|
```
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
You can assign a default tenant if the current tenant is null:
|
130
|
+
To create the database of all tenants.
|
132
131
|
|
133
132
|
```ruby
|
134
|
-
|
133
|
+
rake db:create:all
|
135
134
|
```
|
136
135
|
|
137
|
-
|
138
|
-
specify a criteria to identify the tenant providing a regex as a
|
139
|
-
string. Example, to get the tenant `foo` from the follow url
|
140
|
-
`http://www.example.com/foo/index` you should write:
|
136
|
+
To drop the database of all tenants.
|
141
137
|
|
142
138
|
```ruby
|
143
|
-
|
139
|
+
rake db:drop:all
|
144
140
|
```
|
145
141
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
```ruby
|
150
|
-
config.motel.disable_middleware = true
|
151
|
-
```
|
142
|
+
(Note: Is necessary to establish a **default tenant** because the
|
143
|
+
middlewares of ActiveRecord require a connection to function
|
144
|
+
properly and shared pages between tenants can be viewed.)
|
152
145
|
|
153
146
|
## Use without Rails
|
154
147
|
|
@@ -169,37 +162,32 @@ Motel::Manager.tenants_source_configurations({
|
|
169
162
|
|
170
163
|
## Switching tenants
|
171
164
|
|
172
|
-
|
173
|
-
through the Lobby middleware, otherwise you must set the current
|
174
|
-
tenant:
|
165
|
+
To switch between tenants:
|
175
166
|
|
176
167
|
```ruby
|
177
|
-
Motel::Manager.
|
168
|
+
Motel::Manager.switch_tenant("foo")
|
178
169
|
```
|
179
170
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
```ruby
|
186
|
-
ENV["TENANT"] || Motel::Manager.current_tenant || Motel::Manager.default_tenant
|
187
|
-
```
|
171
|
+
To determine the tenant of the connection to retrieve a fallback is
|
172
|
+
performed through the variables that are used to set the tenant in
|
173
|
+
the following order: environment variable `ENV['TENANT']`,
|
174
|
+
tenant switched `Motel::Manager.switch_tenant()` and default tenant
|
175
|
+
`Motel::Manager.default_tenant`.
|
188
176
|
|
189
177
|
Usage example:
|
190
178
|
|
191
179
|
```ruby
|
192
|
-
Motel::Manager.
|
180
|
+
Motel::Manager.switch_tenant("foo")
|
193
181
|
|
194
182
|
FooBar.create(name: "Foo")
|
195
183
|
# => #<FooBar id: 1, name: "Foo">
|
196
184
|
|
197
|
-
Motel::Manager.
|
185
|
+
Motel::Manager.switch_tenant("bar")
|
198
186
|
|
199
187
|
FooBar.all
|
200
188
|
# => #<ActiveRecord::Relation []>
|
201
189
|
|
202
|
-
Motel::Manager.
|
190
|
+
Motel::Manager.switch_tenant("foo")
|
203
191
|
|
204
192
|
FooBar.all
|
205
193
|
# => #<ActiveRecord::Relation [#<FooBar id: 1, name: "Foo">]>
|
@@ -207,74 +195,69 @@ Usage example:
|
|
207
195
|
|
208
196
|
# Available methods
|
209
197
|
|
210
|
-
|
198
|
+
Sets a tenats source configurations
|
211
199
|
|
212
200
|
```ruby
|
213
201
|
Motel::Manager.tenants_source_configurations(config)
|
214
202
|
```
|
215
203
|
|
216
|
-
|
204
|
+
Switches the tenant
|
217
205
|
|
218
206
|
```ruby
|
219
|
-
Motel::Manager.
|
207
|
+
Motel::Manager.switch_tenant(name)
|
220
208
|
```
|
221
209
|
|
222
|
-
|
210
|
+
Sets a default tenant
|
223
211
|
|
224
212
|
```ruby
|
225
213
|
Motel::Manager.default_tenant
|
226
214
|
```
|
227
215
|
|
228
|
-
|
216
|
+
Retrieves a current tenant
|
229
217
|
|
230
218
|
```ruby
|
231
219
|
Motel::Manager.current_tenant
|
232
220
|
```
|
233
221
|
|
234
|
-
|
222
|
+
Retrieves the connection details of all tenants
|
235
223
|
|
236
224
|
```ruby
|
237
225
|
Motel::Manager.tenants
|
238
226
|
```
|
239
227
|
|
240
|
-
|
228
|
+
Retrieves a tenant
|
241
229
|
|
242
230
|
```ruby
|
243
231
|
Motel::Manager.tenant(name)
|
244
232
|
```
|
245
233
|
|
246
|
-
|
234
|
+
Determines if a tenant exists
|
247
235
|
|
248
236
|
```ruby
|
249
237
|
Motel::Manager.tenant?(name)
|
250
238
|
```
|
251
239
|
|
252
|
-
|
240
|
+
Adds tenant
|
253
241
|
|
254
242
|
```ruby
|
255
243
|
Motel::Manager.add_tenant(name, spec)
|
256
244
|
```
|
257
245
|
|
258
|
-
|
246
|
+
Updates tenant
|
259
247
|
|
260
248
|
```ruby
|
261
249
|
Motel::Manager.update_tenant(name, spec)
|
262
250
|
```
|
263
251
|
|
264
|
-
|
252
|
+
Deletes tenant
|
265
253
|
|
266
254
|
```ruby
|
267
255
|
Motel::Manager.delete_tenant(name)
|
268
256
|
```
|
269
257
|
|
270
|
-
|
258
|
+
Retrieves the names of the tenants of active connections
|
271
259
|
|
272
260
|
```ruby
|
273
261
|
Motel::Manager.active_tenants
|
274
262
|
```
|
275
263
|
|
276
|
-
Determine the tenant to use for the connection
|
277
|
-
|
278
|
-
```ruby
|
279
|
-
Motel::Manager.determines_tenant
|
280
|
-
```
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
data/lib/motel-activerecord.rb
CHANGED
data/lib/motel/active_record.rb
CHANGED
@@ -16,9 +16,15 @@ module Motel
|
|
16
16
|
module ClassMethods
|
17
17
|
|
18
18
|
def establish_connection(config)
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
case config
|
20
|
+
when String, Symbol
|
21
|
+
tenant_name = config.to_s
|
22
|
+
spec = nil
|
23
|
+
else
|
24
|
+
tenant_name = current_tenant
|
25
|
+
resolver = Motel::ConnectionAdapters::ConnectionSpecification::Resolver.new
|
26
|
+
spec = resolver.spec(config)
|
27
|
+
end
|
22
28
|
|
23
29
|
connection_handler.establish_connection tenant_name, spec
|
24
30
|
end
|
@@ -44,7 +50,7 @@ module Motel
|
|
44
50
|
end
|
45
51
|
|
46
52
|
def current_tenant
|
47
|
-
Motel::Manager.
|
53
|
+
Motel::Manager.current_tenant or raise Motel::NoCurrentTenantError
|
48
54
|
end
|
49
55
|
|
50
56
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
db_namespace = namespace :db do
|
4
|
+
|
5
|
+
Rake::Task['db:create:all'].clear
|
6
|
+
namespace :create do
|
7
|
+
task :all => :load_config do
|
8
|
+
Motel::Manager.tenants.each do |tenant_name, config|
|
9
|
+
Motel::Manager.switch_tenant(tenant_name)
|
10
|
+
ActiveRecord::Tasks::DatabaseTasks.create config
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Rake::Task['db:drop:all'].clear
|
16
|
+
namespace :drop do
|
17
|
+
task :all => :load_config do
|
18
|
+
Motel::Manager.tenants.each do |tenant_name, config|
|
19
|
+
Motel::Manager.switch_tenant(tenant_name)
|
20
|
+
ActiveRecord::Tasks::DatabaseTasks.drop config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
if Rake::Task.task_defined?('db:purge:all')
|
26
|
+
Rake::Task['db:purge:all'].clear
|
27
|
+
namespace :purge do
|
28
|
+
task :all => :load_config do
|
29
|
+
Motel::Manager.tenants.each do |tenant_name, config|
|
30
|
+
Motel::Manager.switch_tenant(tenant_name)
|
31
|
+
ActiveRecord::Tasks::DatabaseTasks.purge config
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
data/lib/motel/manager.rb
CHANGED
@@ -5,7 +5,6 @@ require 'active_record'
|
|
5
5
|
module Motel
|
6
6
|
module Manager
|
7
7
|
|
8
|
-
mattr_accessor :admission_criteria
|
9
8
|
mattr_accessor :default_tenant
|
10
9
|
|
11
10
|
class << self
|
@@ -28,7 +27,7 @@ module Motel
|
|
28
27
|
end
|
29
28
|
|
30
29
|
def tenant?(name)
|
31
|
-
|
30
|
+
tenants_source.tenant?(name)
|
32
31
|
end
|
33
32
|
|
34
33
|
def add_tenant(name, spec)
|
@@ -48,36 +47,24 @@ module Motel
|
|
48
47
|
!tenant?(name)
|
49
48
|
end
|
50
49
|
|
50
|
+
def switch_tenant(name)
|
51
|
+
Thread.current.thread_variable_set(:@current_tenant, name)
|
52
|
+
end
|
53
|
+
|
51
54
|
def active_tenants
|
52
55
|
::ActiveRecord::Base.connection_handler.active_tenants
|
53
56
|
end
|
54
57
|
|
55
|
-
def
|
56
|
-
ENV['TENANT'] ||
|
58
|
+
def current_tenant
|
59
|
+
ENV['TENANT'] ||
|
60
|
+
Thread.current.thread_variable_get(:@current_tenant) ||
|
61
|
+
default_tenant
|
57
62
|
end
|
58
63
|
|
59
64
|
def tenants_source
|
60
65
|
::ActiveRecord::Base.connection_handler.tenants_source
|
61
66
|
end
|
62
67
|
|
63
|
-
def current_tenant=(tenant)
|
64
|
-
Thread.current.thread_variable_set(:@current_tenant, tenant)
|
65
|
-
end
|
66
|
-
|
67
|
-
def current_tenant
|
68
|
-
Thread.current.thread_variable_get(:@current_tenant)
|
69
|
-
end
|
70
|
-
|
71
|
-
def nonexistent_tenant_page=(path_page)
|
72
|
-
warn "[DEPRECATION] `nonexistent_tenant_page` is deprecated. The page is manage for ActionDispatch::DebugExceptions middleware."
|
73
|
-
@nonexistent_tenant_page = path_page
|
74
|
-
end
|
75
|
-
|
76
|
-
def nonexistent_tenant_page
|
77
|
-
warn "[DEPRECATION] `nonexistent_tenant_page` is deprecated. The page is manage for ActionDispatch::DebugExceptions middleware."
|
78
|
-
@nonexistent_tenant_page
|
79
|
-
end
|
80
|
-
|
81
68
|
end
|
82
69
|
|
83
70
|
end
|
data/lib/motel/railtie.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'active_support/ordered_options'
|
2
2
|
require 'motel/manager'
|
3
|
+
require 'active_record'
|
3
4
|
require 'rails'
|
5
|
+
require 'active_model/railtie'
|
4
6
|
|
5
7
|
module Motel
|
6
8
|
|
@@ -15,21 +17,21 @@ module Motel
|
|
15
17
|
)
|
16
18
|
|
17
19
|
rake_tasks do
|
20
|
+
require "active_record/base"
|
21
|
+
|
18
22
|
namespace :db do
|
19
23
|
task :load_config do
|
20
24
|
Motel::Manager.tenants_source_configurations(
|
21
25
|
Rails.application.config.motel.tenants_source_configurations
|
22
26
|
)
|
23
27
|
|
24
|
-
# Set a current tenant allow to db:create:all task establish and
|
25
|
-
# retrieve the connection
|
26
|
-
Motel::Manager.current_tenant ||= self.class
|
27
|
-
|
28
28
|
::ActiveRecord::Tasks::DatabaseTasks.database_configuration = Motel::Manager.tenants
|
29
29
|
::ActiveRecord::Base.configurations = ::ActiveRecord::Tasks::DatabaseTasks.database_configuration
|
30
|
-
::ActiveRecord::Tasks::DatabaseTasks.env = Motel::Manager.
|
30
|
+
::ActiveRecord::Tasks::DatabaseTasks.env = Motel::Manager.current_tenant
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
load "motel/active_record/railties/databases.rake"
|
33
35
|
end
|
34
36
|
|
35
37
|
::ActiveRecord::Railtie.initializers.delete_if do |i|
|
@@ -39,19 +41,10 @@ module Motel
|
|
39
41
|
initializer "motel.general_configuration" do
|
40
42
|
motel_config = Rails.application.config.motel
|
41
43
|
|
42
|
-
Motel::Manager.nonexistent_tenant_page = motel_config.nonexistent_tenant_page || 'public/404.html' # Deprecated
|
43
|
-
Motel::Manager.admission_criteria = motel_config.admission_criteria
|
44
44
|
Motel::Manager.default_tenant = motel_config.default_tenant
|
45
45
|
Motel::Manager.tenants_source_configurations(motel_config.tenants_source_configurations)
|
46
46
|
end
|
47
47
|
|
48
|
-
# Set lobby middleware before all ActiveRecord's middlewares
|
49
|
-
initializer "motel.configure_middleware" do |app|
|
50
|
-
if !Rails.application.config.motel.disable_middleware && (Rails.env != 'test')
|
51
|
-
app.config.middleware.insert_after ActionDispatch::Callbacks, Lobby
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
48
|
initializer "active_record.set_reloader_hooks" do |app|
|
56
49
|
hook = app.config.reload_classes_only_on_change ? :to_prepare : :to_cleanup
|
57
50
|
|
@@ -59,7 +52,7 @@ module Motel
|
|
59
52
|
ActionDispatch::Reloader.send(hook) do
|
60
53
|
::ActiveRecord::Base.clear_reloadable_connections!
|
61
54
|
# Clear cache of the current tenant with an active connection
|
62
|
-
if Motel::Manager.active_tenants.include?(Motel::Manager.
|
55
|
+
if Motel::Manager.active_tenants.include?(Motel::Manager.current_tenant)
|
63
56
|
::ActiveRecord::Base.clear_cache!
|
64
57
|
end
|
65
58
|
end
|
@@ -17,31 +17,60 @@ describe ::ActiveRecord::Base do
|
|
17
17
|
::ActiveRecord::Base.connection_handler.active_tenants do |tenant|
|
18
18
|
::ActiveRecord::Base.connection_handler.remove_connection(tenant)
|
19
19
|
end
|
20
|
-
Motel::Manager.
|
20
|
+
Motel::Manager.switch_tenant(nil)
|
21
|
+
ENV['TENANT'] = nil
|
21
22
|
end
|
22
23
|
|
23
24
|
describe '.establish_connection' do
|
24
25
|
|
25
|
-
context '
|
26
|
+
context 'with a connection specification' do
|
27
|
+
|
28
|
+
context 'and the environment variable of the current is established' do
|
29
|
+
|
30
|
+
before(:each) do
|
31
|
+
ENV['TENANT'] = 'foo'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'establishes a connection keyed by tenant name' do
|
35
|
+
::ActiveRecord::Base.establish_connection(FOO_SPEC)
|
36
|
+
|
37
|
+
expect(::ActiveRecord::Base.connection_handler.active_tenants).to include('foo')
|
38
|
+
end
|
26
39
|
|
27
|
-
before(:each) do
|
28
|
-
Motel::Manager.current_tenant = 'foo'
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
|
-
|
42
|
+
context 'and the environment variable of the current is not established' do
|
43
|
+
|
44
|
+
it 'establishes a connection keyed by name of the class' do
|
45
|
+
::ActiveRecord::Base.establish_connection(FOO_SPEC)
|
46
|
+
|
47
|
+
expect(::ActiveRecord::Base.connection_handler.active_tenants).to include('ActiveRecord::Base')
|
48
|
+
end
|
33
49
|
|
34
|
-
expect(::ActiveRecord::Base.connection_handler.active_tenants).to include('foo')
|
35
50
|
end
|
36
51
|
|
37
52
|
end
|
38
53
|
|
39
|
-
context '
|
54
|
+
context 'with a tenant name' do
|
55
|
+
|
56
|
+
context 'existent' do
|
57
|
+
|
58
|
+
it 'establishes a connection keyed by tenant name' do
|
59
|
+
::ActiveRecord::Base.establish_connection('foo')
|
60
|
+
|
61
|
+
expect(::ActiveRecord::Base.connection_handler.active_tenants).to include('foo')
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'nonexistent' do
|
40
67
|
|
41
|
-
|
42
|
-
|
68
|
+
it 'raises an error' do
|
69
|
+
expect{
|
70
|
+
::ActiveRecord::Base.establish_connection('baz')
|
71
|
+
}.to raise_error Motel::NonexistentTenantError
|
72
|
+
end
|
43
73
|
|
44
|
-
expect(::ActiveRecord::Base.connection_handler.active_tenants).to include('ActiveRecord::Base')
|
45
74
|
end
|
46
75
|
|
47
76
|
end
|
@@ -53,7 +82,7 @@ describe ::ActiveRecord::Base do
|
|
53
82
|
context 'current tenant established' do
|
54
83
|
|
55
84
|
it 'returns a connection pool of current tenant' do
|
56
|
-
Motel::Manager.
|
85
|
+
Motel::Manager.switch_tenant('foo')
|
57
86
|
pool = ::ActiveRecord::Base.connection_handler.establish_connection('foo')
|
58
87
|
|
59
88
|
expect(::ActiveRecord::Base.connection_pool).to eq pool
|
@@ -64,7 +93,7 @@ describe ::ActiveRecord::Base do
|
|
64
93
|
context 'current tenant not established' do
|
65
94
|
|
66
95
|
it 'rises an error' do
|
67
|
-
Motel::Manager.
|
96
|
+
Motel::Manager.switch_tenant(nil)
|
68
97
|
expect{::ActiveRecord::Base.connection_pool}.to raise_error Motel::NoCurrentTenantError
|
69
98
|
end
|
70
99
|
|
@@ -77,7 +106,7 @@ describe ::ActiveRecord::Base do
|
|
77
106
|
context 'current tenant established' do
|
78
107
|
|
79
108
|
it 'returns a connection of current tenant' do
|
80
|
-
Motel::Manager.
|
109
|
+
Motel::Manager.switch_tenant('foo')
|
81
110
|
pool = ::ActiveRecord::Base.connection_handler.establish_connection('foo')
|
82
111
|
|
83
112
|
expect(::ActiveRecord::Base.retrieve_connection).to eq pool.connection
|
@@ -88,7 +117,7 @@ describe ::ActiveRecord::Base do
|
|
88
117
|
context 'current tenant not established' do
|
89
118
|
|
90
119
|
it 'rises an error' do
|
91
|
-
Motel::Manager.
|
120
|
+
Motel::Manager.switch_tenant(nil)
|
92
121
|
expect{::ActiveRecord::Base.retrieve_connection}.to raise_error Motel::NoCurrentTenantError
|
93
122
|
end
|
94
123
|
|
@@ -105,12 +134,12 @@ describe ::ActiveRecord::Base do
|
|
105
134
|
context 'current tenant established' do
|
106
135
|
|
107
136
|
it 'returns true' do
|
108
|
-
Motel::Manager.
|
137
|
+
Motel::Manager.switch_tenant('foo')
|
109
138
|
expect(::ActiveRecord::Base.connected?).to be_truthy
|
110
139
|
end
|
111
140
|
|
112
141
|
it 'returns false' do
|
113
|
-
Motel::Manager.
|
142
|
+
Motel::Manager.switch_tenant('bar')
|
114
143
|
expect(::ActiveRecord::Base.connected?).to be_falsey
|
115
144
|
end
|
116
145
|
|
@@ -119,7 +148,7 @@ describe ::ActiveRecord::Base do
|
|
119
148
|
context 'current tenant not established' do
|
120
149
|
|
121
150
|
it 'rises an error' do
|
122
|
-
Motel::Manager.
|
151
|
+
Motel::Manager.switch_tenant(nil)
|
123
152
|
expect{::ActiveRecord::Base.connected?}.to raise_error Motel::NoCurrentTenantError
|
124
153
|
end
|
125
154
|
|
@@ -133,7 +162,7 @@ describe ::ActiveRecord::Base do
|
|
133
162
|
|
134
163
|
it 'removes connection' do
|
135
164
|
::ActiveRecord::Base.connection_handler.establish_connection('foo')
|
136
|
-
Motel::Manager.
|
165
|
+
Motel::Manager.switch_tenant('foo')
|
137
166
|
::ActiveRecord::Base.remove_connection
|
138
167
|
expect(::ActiveRecord::Base.connection_handler.active_tenants).not_to include('foo')
|
139
168
|
end
|
@@ -143,7 +172,7 @@ describe ::ActiveRecord::Base do
|
|
143
172
|
context 'current tenant not established' do
|
144
173
|
|
145
174
|
it 'rises an error' do
|
146
|
-
Motel::Manager.
|
175
|
+
Motel::Manager.switch_tenant(nil)
|
147
176
|
expect{::ActiveRecord::Base.remove_connection}.to raise_error Motel::NoCurrentTenantError
|
148
177
|
end
|
149
178
|
|
@@ -164,7 +193,7 @@ describe ::ActiveRecord::Base do
|
|
164
193
|
context 'tenant enviroment variable or current tenant or default tenant are set' do
|
165
194
|
|
166
195
|
it 'returns the current tenant' do
|
167
|
-
Motel::Manager.
|
196
|
+
Motel::Manager.switch_tenant('foo')
|
168
197
|
|
169
198
|
expect(::ActiveRecord::Base.current_tenant).to eq 'foo'
|
170
199
|
end
|
@@ -174,7 +203,7 @@ describe ::ActiveRecord::Base do
|
|
174
203
|
context 'no tenant has been established' do
|
175
204
|
|
176
205
|
it 'rises an error' do
|
177
|
-
Motel::Manager.
|
206
|
+
Motel::Manager.switch_tenant(nil)
|
178
207
|
|
179
208
|
expect{::ActiveRecord::Base.current_tenant}.to raise_error Motel::NoCurrentTenantError
|
180
209
|
end
|
@@ -20,7 +20,7 @@ describe Motel::Manager do
|
|
20
20
|
|
21
21
|
after(:each) do
|
22
22
|
ENV['TENANT'] = nil
|
23
|
-
@manager.
|
23
|
+
@manager.switch_tenant(nil)
|
24
24
|
@manager.default_tenant = nil
|
25
25
|
|
26
26
|
# Remove all connections tenant
|
@@ -120,14 +120,6 @@ describe Motel::Manager do
|
|
120
120
|
expect(@manager.tenant?('foo')).to be_truthy
|
121
121
|
end
|
122
122
|
|
123
|
-
it 'returns true if tenant baz does exist' do
|
124
|
-
resolver = Motel::ConnectionAdapters::ConnectionSpecification::Resolver.new
|
125
|
-
spec = resolver.spec(BAZ_SPEC)
|
126
|
-
handler = ::ActiveRecord::Base.connection_handler
|
127
|
-
handler.establish_connection('baz', spec)
|
128
|
-
expect(@manager.tenant?('baz')).to be_truthy
|
129
|
-
end
|
130
|
-
|
131
123
|
it 'returns false if tenant does not exist' do
|
132
124
|
expect(@manager.tenant?('foobar')).to be_falsey
|
133
125
|
end
|
@@ -193,16 +185,17 @@ describe Motel::Manager do
|
|
193
185
|
|
194
186
|
end
|
195
187
|
|
196
|
-
describe '#
|
188
|
+
describe '#current_tenant' do
|
197
189
|
|
198
190
|
context 'tenant environment variable, current tenant and default tenant are set' do
|
199
191
|
|
200
192
|
it 'returns tenant enviroment variable' do
|
201
193
|
ENV['TENANT'] = 'foo'
|
202
|
-
@manager.current_tenant = 'bar'
|
203
194
|
@manager.default_tenant = 'baz'
|
204
195
|
|
205
|
-
|
196
|
+
@manager.switch_tenant('bar')
|
197
|
+
|
198
|
+
expect(@manager.current_tenant).to eq ENV['TENANT']
|
206
199
|
end
|
207
200
|
|
208
201
|
end
|
@@ -211,10 +204,11 @@ describe Motel::Manager do
|
|
211
204
|
|
212
205
|
it 'returns tenant enviroment variable' do
|
213
206
|
ENV['TENANT'] = nil
|
214
|
-
@manager.current_tenant = 'bar'
|
215
207
|
@manager.default_tenant = 'baz'
|
216
208
|
|
217
|
-
|
209
|
+
@manager.switch_tenant('bar')
|
210
|
+
|
211
|
+
expect(@manager.current_tenant).to eq 'bar'
|
218
212
|
end
|
219
213
|
|
220
214
|
end
|
@@ -223,10 +217,11 @@ describe Motel::Manager do
|
|
223
217
|
|
224
218
|
it 'returns tenant enviroment variable' do
|
225
219
|
ENV['TENANT'] = nil
|
226
|
-
@manager.current_tenant = nil
|
227
220
|
@manager.default_tenant = 'baz'
|
228
221
|
|
229
|
-
|
222
|
+
@manager.switch_tenant(nil)
|
223
|
+
|
224
|
+
expect(@manager.current_tenant).to eq 'baz'
|
230
225
|
end
|
231
226
|
|
232
227
|
end
|
data/spec/tmp/tenants.sqlite3
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motel-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Diego Martínez Valdelamar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -128,10 +128,8 @@ files:
|
|
128
128
|
- lib/motel/connection_adapters/connection_specification/resolver.rb
|
129
129
|
- lib/motel/connection_adapters/connection_specification.rb
|
130
130
|
- lib/motel/connection_adapters/connection_handler.rb
|
131
|
-
- lib/motel/lobby.rb
|
132
|
-
- lib/motel/active_record/query_cache.rb
|
133
|
-
- lib/motel/active_record/migration.rb
|
134
131
|
- lib/motel/active_record/connection_handler.rb
|
132
|
+
- lib/motel/active_record/railties/databases.rake
|
135
133
|
- VERSION
|
136
134
|
- README.md
|
137
135
|
- spec/tmp/foo.sqlite3
|
@@ -142,7 +140,6 @@ files:
|
|
142
140
|
- spec/lib/motel/sources/redis_spec.rb
|
143
141
|
- spec/lib/motel/connection_adapters/connection_specification/resolver_spec.rb
|
144
142
|
- spec/lib/motel/connection_adapters/connection_handler_spec.rb
|
145
|
-
- spec/lib/motel/lobby_spec.rb
|
146
143
|
- spec/lib/motel/manager_spec.rb
|
147
144
|
- spec/lib/motel/active_record/connection_handler.rb
|
148
145
|
homepage: https://github.com/dimarval/motel-activerecord
|
@@ -178,7 +175,6 @@ test_files:
|
|
178
175
|
- spec/lib/motel/sources/redis_spec.rb
|
179
176
|
- spec/lib/motel/connection_adapters/connection_specification/resolver_spec.rb
|
180
177
|
- spec/lib/motel/connection_adapters/connection_handler_spec.rb
|
181
|
-
- spec/lib/motel/lobby_spec.rb
|
182
178
|
- spec/lib/motel/manager_spec.rb
|
183
179
|
- spec/lib/motel/active_record/connection_handler.rb
|
184
180
|
has_rdoc:
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
module Motel
|
4
|
-
module ActiveRecord
|
5
|
-
module Migration
|
6
|
-
module CheckPending
|
7
|
-
|
8
|
-
def call(env)
|
9
|
-
return @app.call(env) unless Motel::Manager.determines_tenant
|
10
|
-
|
11
|
-
if connection.supports_migrations?
|
12
|
-
mtime = ::ActiveRecord::Migrator.last_migration.mtime.to_i
|
13
|
-
if @last_check < mtime
|
14
|
-
::ActiveRecord::Migration.check_pending!(connection)
|
15
|
-
@last_check = mtime
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
@app.call(env)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def connection
|
25
|
-
::ActiveRecord::Base.connection
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class ActiveRecord::Migration::CheckPending
|
34
|
-
prepend Motel::ActiveRecord::Migration::CheckPending
|
35
|
-
end
|
36
|
-
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
module Motel
|
4
|
-
module ActiveRecord
|
5
|
-
module QueryCache
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
|
9
|
-
# Enable the query cache within the block if Active Record is configured.
|
10
|
-
# If it's not, it will execute the given block.
|
11
|
-
def cache(&block)
|
12
|
-
if Motel::Manager.determines_tenant &&
|
13
|
-
::ActiveRecord::Base.connected?
|
14
|
-
connection.cache(&block)
|
15
|
-
else
|
16
|
-
yield
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Disable the query cache within the block if Active Record is configured.
|
21
|
-
# If it's not, it will execute the given block.
|
22
|
-
def uncached(&block)
|
23
|
-
if Motel::Manager.determines_tenant &&
|
24
|
-
::ActiveRecord::Base.connected?
|
25
|
-
connection.uncached(&block)
|
26
|
-
else
|
27
|
-
yield
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
def call(env)
|
34
|
-
if Motel::Manager.determines_tenant
|
35
|
-
connection = ::ActiveRecord::Base.connection
|
36
|
-
enabled = connection.query_cache_enabled
|
37
|
-
connection_id = ::ActiveRecord::Base.connection_id
|
38
|
-
connection.enable_query_cache!
|
39
|
-
|
40
|
-
response = @app.call(env)
|
41
|
-
response[2] = Rack::BodyProxy.new(response[2]) do
|
42
|
-
restore_query_cache_settings(connection_id, enabled)
|
43
|
-
end
|
44
|
-
|
45
|
-
response
|
46
|
-
else
|
47
|
-
@app.call(env)
|
48
|
-
end
|
49
|
-
rescue Exception => e
|
50
|
-
if Motel::Manager.determines_tenant
|
51
|
-
restore_query_cache_settings(connection_id, enabled)
|
52
|
-
end
|
53
|
-
|
54
|
-
raise e
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class ::ActiveRecord::Base
|
63
|
-
extend Motel::ActiveRecord::QueryCache::ClassMethods
|
64
|
-
end
|
65
|
-
|
66
|
-
class ::ActiveRecord::QueryCache
|
67
|
-
prepend Motel::ActiveRecord::QueryCache
|
68
|
-
end
|
69
|
-
|
70
|
-
class ::ActiveRecord::ConnectionAdapters::AbstractAdapter
|
71
|
-
prepend Motel::ActiveRecord::QueryCache::ClassMethods
|
72
|
-
end
|
73
|
-
|
data/lib/motel/lobby.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'rack'
|
2
|
-
|
3
|
-
module Motel
|
4
|
-
|
5
|
-
class Lobby
|
6
|
-
|
7
|
-
def initialize(app)
|
8
|
-
@app = app
|
9
|
-
end
|
10
|
-
|
11
|
-
def call(env)
|
12
|
-
request = Rack::Request.new(env)
|
13
|
-
name = tenant_name(request)
|
14
|
-
|
15
|
-
if name && Motel::Manager.tenant?(name)
|
16
|
-
Motel::Manager.current_tenant = name
|
17
|
-
else
|
18
|
-
Motel::Manager.current_tenant = nil
|
19
|
-
end
|
20
|
-
|
21
|
-
@app.call(env)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def tenant_name(request)
|
27
|
-
if Motel::Manager.admission_criteria
|
28
|
-
regex = Regexp.new(Motel::Manager.admission_criteria)
|
29
|
-
name = request.path.match(regex)
|
30
|
-
name[1] if name
|
31
|
-
else
|
32
|
-
request.host.split('.').first
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
@@ -1,133 +0,0 @@
|
|
1
|
-
ENV['RACK_ENV'] = 'test'
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'rack/test'
|
5
|
-
require 'tempfile'
|
6
|
-
|
7
|
-
describe Motel::Lobby do
|
8
|
-
include Rack::Test::Methods
|
9
|
-
|
10
|
-
def app
|
11
|
-
app = lambda{ |env| [200, {"Content-Type" => "text/html"}, "Test"] }
|
12
|
-
Motel::Lobby.new(app)
|
13
|
-
end
|
14
|
-
|
15
|
-
before(:all) do
|
16
|
-
Motel::Manager.add_tenant('foo', FOO_SPEC)
|
17
|
-
end
|
18
|
-
|
19
|
-
after(:all) do
|
20
|
-
Motel::Manager.delete_tenant('foo')
|
21
|
-
Motel::Manager.admission_criteria = nil #sets default
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#call' do
|
25
|
-
|
26
|
-
context 'default admission criteria' do
|
27
|
-
|
28
|
-
before(:all) do
|
29
|
-
Motel::Manager.admission_criteria = nil
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'url match' do
|
33
|
-
|
34
|
-
context 'existing tenant' do
|
35
|
-
|
36
|
-
before(:each) do
|
37
|
-
@url = 'http://foo.test.com'
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'sets the current tenant' do
|
41
|
-
request @url
|
42
|
-
|
43
|
-
expect(Motel::Manager.current_tenant).to eq 'foo'
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'response is ok' do
|
47
|
-
request @url
|
48
|
-
|
49
|
-
expect(last_response).to be_ok
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
context 'nonexistent tenant' do
|
55
|
-
|
56
|
-
before(:each) do
|
57
|
-
@url = 'http://bar.test.com'
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'sets the current tenant on nil' do
|
61
|
-
request @url
|
62
|
-
|
63
|
-
expect(Motel::Manager.current_tenant).to be_nil
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'response is ok' do
|
67
|
-
request @url
|
68
|
-
|
69
|
-
expect(last_response).to be_ok
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
context 'specifying admission criteria' do
|
81
|
-
|
82
|
-
before(:all) do
|
83
|
-
Motel::Manager.admission_criteria = 'tenants\/(\w*)'
|
84
|
-
end
|
85
|
-
|
86
|
-
context 'url match' do
|
87
|
-
|
88
|
-
context 'existing tenant' do
|
89
|
-
|
90
|
-
before(:each) do
|
91
|
-
@url = 'http://www.example.com/tenants/foo'
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'sets the current tenant' do
|
95
|
-
request @url
|
96
|
-
|
97
|
-
expect(Motel::Manager.current_tenant).to eq 'foo'
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'response is ok' do
|
101
|
-
request @url
|
102
|
-
|
103
|
-
expect(last_response).to be_ok
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
context 'url does not match' do
|
111
|
-
|
112
|
-
before(:each) do
|
113
|
-
@url = 'http://example.com'
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'sets null the current tenant' do
|
117
|
-
request @url
|
118
|
-
|
119
|
-
expect(Motel::Manager.current_tenant).to be_nil
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'response is ok' do
|
123
|
-
request @url
|
124
|
-
|
125
|
-
expect(last_response).to be_ok
|
126
|
-
end
|
127
|
-
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
|