acts_as_tenant 0.3.3 → 0.3.4
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 +8 -8
- data/CHANGELOG.md +4 -1
- data/README.md +10 -0
- data/acts_as_tenant.gemspec +2 -0
- data/lib/acts_as_tenant/model_extensions.rb +13 -12
- data/lib/acts_as_tenant/sidekiq.rb +43 -0
- data/lib/acts_as_tenant/version.rb +1 -1
- data/spec/acts_as_tenant/model_extensions_spec.rb +23 -1
- data/spec/acts_as_tenant/sidekiq_spec.rb +63 -0
- metadata +19 -2
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
MDI0NjdkNWMzYTNjMDk2OTI4YjIxMmM1YmNmOThmOGVkYmU5MGQ1Yg==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
MjIxYTJjNmU0MTI1ZGJiZjEyNDNiOTcyMjhjNDk5Yjg5ZjExZDA3ZA==
|
|
7
7
|
SHA512:
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
MzUxZmM0MzIyMjM1NWMxMThmNjk5NDE0NmUyYzNjMDk3NWNlODI0NWM3YWIw
|
|
10
|
+
NjVjMmMxOGZhODRjZDJiOTRmYjJkZjQ3YmJjZDc0YzgwZTBiNDRmY2ZkMjdk
|
|
11
|
+
MzU2MTBlYTZjM2EzODM1NTY4OGVkMGU3YzU5ZTA3MzdjMzA1ODc=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
YjY1ZjM4Yzc5ZTJkZTU3Y2YyNDU1MjMxNjI0OGVlYzQ1NDA2ODA3NTgzY2Ex
|
|
14
|
+
Zjg1MGM5YTdiMDNkNWQwZTUxZGZlZDljNmEzYjYxZDEzYmM3NTJmYjQxZDVi
|
|
15
|
+
NGEyMGY2MGE4MzRmMzFjMzU3OWZjZWE0NDg0ZTQ1NGMxZmYwOWY=
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
0.3.4
|
|
2
|
+
-----
|
|
3
|
+
* Fix to a bug introduced in 0.3.2
|
|
4
|
+
|
|
1
5
|
0.3.3
|
|
2
6
|
-----
|
|
3
7
|
* Support user defined foreign keys on scoped models
|
|
@@ -6,7 +10,6 @@
|
|
|
6
10
|
-----
|
|
7
11
|
* correctly support nested models with has_many :through (thx dexion)
|
|
8
12
|
* Support 'www.subdomain.example.com' (thx wtfiwtz)
|
|
9
|
-
* Support user defined foreign keys on scoped models
|
|
10
13
|
* Support setting `tenant_id` on scoped models if the `tenant_id` is nil (thx Matt Wilson)
|
|
11
14
|
|
|
12
15
|
0.3.1
|
data/README.md
CHANGED
|
@@ -136,6 +136,16 @@ end
|
|
|
136
136
|
|
|
137
137
|
* `config.require_tenant` when set to true will raise an ActsAsTenant::NoTenant error whenever a query is made without a tenant set.
|
|
138
138
|
|
|
139
|
+
Sidekiq support
|
|
140
|
+
---------------
|
|
141
|
+
|
|
142
|
+
ActsAsTenant supports [Sidekiq](http://sidekiq.org/). A background processing library.
|
|
143
|
+
Add the following code to your `config/initializer/acts_as_tenant.rb`:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
require 'acts_as_tenant/sidekiq'
|
|
147
|
+
```
|
|
148
|
+
|
|
139
149
|
Note on testing
|
|
140
150
|
---------------
|
|
141
151
|
Whenever you set the `current_tenant` in your tests, either through integration tests or directly by calling `ActsAsTenant.current_tenant = some_tenant`, make sure to clean up the tenant after each test by calling `ActsAsTenant.current_tenant = nil`.
|
data/acts_as_tenant.gemspec
CHANGED
|
@@ -42,16 +42,12 @@ module ActsAsTenant
|
|
|
42
42
|
|
|
43
43
|
module ClassMethods
|
|
44
44
|
def acts_as_tenant(tenant = :account, options = {})
|
|
45
|
-
|
|
46
45
|
ActsAsTenant.set_tenant_klass(tenant)
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
fkey = ActsAsTenant.fkey
|
|
53
|
-
belongs_to tenant
|
|
54
|
-
end
|
|
47
|
+
# Create the association
|
|
48
|
+
valid_options = options.slice(:foreign_key, :class_name)
|
|
49
|
+
fkey = valid_options[:foreign_key] || ActsAsTenant.fkey
|
|
50
|
+
belongs_to tenant, valid_options
|
|
55
51
|
|
|
56
52
|
default_scope lambda {
|
|
57
53
|
if ActsAsTenant.configuration.require_tenant && ActsAsTenant.current_tenant.nil?
|
|
@@ -95,12 +91,17 @@ module ActsAsTenant
|
|
|
95
91
|
end
|
|
96
92
|
|
|
97
93
|
define_method "#{ActsAsTenant.tenant_klass.to_s}" do
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
if !ActsAsTenant.current_tenant.nil? && send(fkey) == ActsAsTenant.current_tenant.id
|
|
95
|
+
return ActsAsTenant.current_tenant
|
|
96
|
+
else
|
|
97
|
+
super()
|
|
98
|
+
end
|
|
100
99
|
end
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
class << self
|
|
102
|
+
def scoped_by_tenant?
|
|
103
|
+
true
|
|
104
|
+
end
|
|
104
105
|
end
|
|
105
106
|
end
|
|
106
107
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module ActsAsTenant::Sidekiq
|
|
2
|
+
# Get the current tenant and store in the message to be sent to Sidekiq.
|
|
3
|
+
class Client
|
|
4
|
+
def call(worker_class, msg, queue)
|
|
5
|
+
msg['acts_as_tenant'] ||=
|
|
6
|
+
{
|
|
7
|
+
'class' => ActsAsTenant.current_tenant.class.name,
|
|
8
|
+
'id' => ActsAsTenant.current_tenant.id
|
|
9
|
+
} if ActsAsTenant.current_tenant.present?
|
|
10
|
+
|
|
11
|
+
yield
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Pull the tenant out and run the current thread with it.
|
|
16
|
+
class Server
|
|
17
|
+
def call(worker_class, msg, queue)
|
|
18
|
+
if msg.has_key?('acts_as_tenant')
|
|
19
|
+
account = msg['acts_as_tenant']['class'].constantize.find msg['acts_as_tenant']['id']
|
|
20
|
+
ActsAsTenant.with_tenant account do
|
|
21
|
+
yield
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
yield
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Sidekiq.configure_client do |config|
|
|
31
|
+
config.client_middleware do |chain|
|
|
32
|
+
chain.add ActsAsTenant::Sidekiq::Client
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Sidekiq.configure_server do |config|
|
|
37
|
+
config.client_middleware do |chain|
|
|
38
|
+
chain.add ActsAsTenant::Sidekiq::Client
|
|
39
|
+
end
|
|
40
|
+
config.server_middleware do |chain|
|
|
41
|
+
chain.add ActsAsTenant::Sidekiq::Server
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -109,10 +109,14 @@ describe ActsAsTenant do
|
|
|
109
109
|
it { ActsAsTenant.current_tenant == :foo }
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
describe 'is_scoped_as_tenant should return the correct value' do
|
|
112
|
+
describe 'is_scoped_as_tenant should return the correct value when true' do
|
|
113
113
|
it {Project.respond_to?(:scoped_by_tenant?).should == true}
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
+
describe 'is_scoped_as_tenant should return the correct value when false' do
|
|
117
|
+
it {UnscopedModel.respond_to?(:scoped_by_tenant?).should == false}
|
|
118
|
+
end
|
|
119
|
+
|
|
116
120
|
describe 'tenant_id should be immutable, if already set' do
|
|
117
121
|
before do
|
|
118
122
|
@account = Account.create!(:name => 'foo')
|
|
@@ -174,6 +178,24 @@ describe ActsAsTenant do
|
|
|
174
178
|
it { @projects.count.should == 2 }
|
|
175
179
|
end
|
|
176
180
|
|
|
181
|
+
describe 'Querying the tenant from a scoped model without a tenant set' do
|
|
182
|
+
before do
|
|
183
|
+
@project = Project.create!(:name => 'bar')
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it { @project.account }
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
describe 'Querying the tenant from a scoped model with a tenant set' do
|
|
190
|
+
before do
|
|
191
|
+
@account = Account.create!(:name => 'foo')
|
|
192
|
+
@project = @account.projects.create!(:name => 'foobar')
|
|
193
|
+
ActsAsTenant.current_tenant= @account1
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it { @project.account }
|
|
197
|
+
end
|
|
198
|
+
|
|
177
199
|
# Associations
|
|
178
200
|
describe 'Associations should be correctly scoped by current tenant' do
|
|
179
201
|
before do
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'sidekiq'
|
|
3
|
+
require 'acts_as_tenant/sidekiq'
|
|
4
|
+
|
|
5
|
+
describe ActsAsTenant::Sidekiq do
|
|
6
|
+
after { ActsAsTenant.current_tenant = nil }
|
|
7
|
+
let(:account) { Account.new(id: 1234) }
|
|
8
|
+
let(:message) { { 'acts_as_tenant' => { 'class' => 'Account', 'id' => 1234 } } }
|
|
9
|
+
|
|
10
|
+
describe ActsAsTenant::Sidekiq::Client do
|
|
11
|
+
subject { ActsAsTenant::Sidekiq::Client.new }
|
|
12
|
+
|
|
13
|
+
it 'saves tenant if present' do
|
|
14
|
+
ActsAsTenant.current_tenant = account
|
|
15
|
+
|
|
16
|
+
msg = {}
|
|
17
|
+
subject.call(nil, msg, nil) { }
|
|
18
|
+
expect(msg).to eq message
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'does not set tenant if not present' do
|
|
22
|
+
expect(ActsAsTenant.current_tenant).to be_nil
|
|
23
|
+
|
|
24
|
+
msg = {}
|
|
25
|
+
subject.call(nil, msg, nil) { }
|
|
26
|
+
expect(msg).not_to eq message
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe ActsAsTenant::Sidekiq::Server do
|
|
31
|
+
subject { ActsAsTenant::Sidekiq::Server.new }
|
|
32
|
+
|
|
33
|
+
it 'restores tenant if tenant saved' do
|
|
34
|
+
expect(Account).to receive(:find).with(1234).once { account }
|
|
35
|
+
|
|
36
|
+
msg = message
|
|
37
|
+
subject.call(nil, msg, nil) do
|
|
38
|
+
expect(ActsAsTenant.current_tenant).to be_a_kind_of Account
|
|
39
|
+
end
|
|
40
|
+
expect(ActsAsTenant.current_tenant).to be_nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'runs without tenant if no tenant saved' do
|
|
44
|
+
expect(Account).not_to receive(:find)
|
|
45
|
+
|
|
46
|
+
msg = {}
|
|
47
|
+
subject.call(nil, msg, nil) do
|
|
48
|
+
expect(ActsAsTenant.current_tenant).to be_nil
|
|
49
|
+
end
|
|
50
|
+
expect(ActsAsTenant.current_tenant).to be_nil
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe 'Sidekiq configuration' do
|
|
55
|
+
describe 'client configuration' do
|
|
56
|
+
it 'includes ActsAsTenant client' do
|
|
57
|
+
expect(Sidekiq.client_middleware.exists?(ActsAsTenant::Sidekiq::Client)).to be_true
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# unable to test server configuration
|
|
62
|
+
end
|
|
63
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acts_as_tenant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Erwin Matthijssen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-01-
|
|
11
|
+
date: 2014-01-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: request_store
|
|
@@ -108,6 +108,20 @@ dependencies:
|
|
|
108
108
|
- - ! '>='
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: sidekiq
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ! '>='
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ! '>='
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
111
125
|
description: Integrates multi-tenancy into a Rails application in a convenient and
|
|
112
126
|
out-of-your way manner
|
|
113
127
|
email:
|
|
@@ -128,10 +142,12 @@ files:
|
|
|
128
142
|
- lib/acts_as_tenant/controller_extensions.rb
|
|
129
143
|
- lib/acts_as_tenant/errors.rb
|
|
130
144
|
- lib/acts_as_tenant/model_extensions.rb
|
|
145
|
+
- lib/acts_as_tenant/sidekiq.rb
|
|
131
146
|
- lib/acts_as_tenant/version.rb
|
|
132
147
|
- rails/init.rb
|
|
133
148
|
- spec/acts_as_tenant/configuration_spec.rb
|
|
134
149
|
- spec/acts_as_tenant/model_extensions_spec.rb
|
|
150
|
+
- spec/acts_as_tenant/sidekiq_spec.rb
|
|
135
151
|
- spec/acts_as_tenant/tenant_by_filter_spec.rb
|
|
136
152
|
- spec/acts_as_tenant/tenant_by_subdomain_spec.rb
|
|
137
153
|
- spec/database.yml
|
|
@@ -162,6 +178,7 @@ summary: Add multi-tenancy to Rails applications using a shared db strategy
|
|
|
162
178
|
test_files:
|
|
163
179
|
- spec/acts_as_tenant/configuration_spec.rb
|
|
164
180
|
- spec/acts_as_tenant/model_extensions_spec.rb
|
|
181
|
+
- spec/acts_as_tenant/sidekiq_spec.rb
|
|
165
182
|
- spec/acts_as_tenant/tenant_by_filter_spec.rb
|
|
166
183
|
- spec/acts_as_tenant/tenant_by_subdomain_spec.rb
|
|
167
184
|
- spec/database.yml
|