acts_as_tenant 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZTU3MTcwNGYyNzk1NDk3OWMyNmQxYWJjNDdkNjI5NDVjZjc4MjA0MQ==
5
- data.tar.gz: !binary |-
6
- NTUxMDJkZmI1NmE3MGY3NzliMzI5N2ZiOGY4MTA1ZGQyZDlkNDRlYg==
2
+ SHA1:
3
+ metadata.gz: b818ac81194035979865164439e777511f68c06c
4
+ data.tar.gz: f395680cfb279dd618df7e88ca6373adb2f6596a
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZDFkMWRmYjRhNTdmZmYxNDFmOWE4YjYxNTVhMTU0ZDYxNjE3OTk2Yjk0Yzdh
10
- OWRlZGFmODNlN2E1NWJlNmRmNmVkYTEzOWVlOGViODBlNzY5YmYxY2QzMDZl
11
- NTgwMjU5MjU3MGFkN2Q5MzBkY2MwMzljMDhiNTViZTI1ZmY3OTk=
12
- data.tar.gz: !binary |-
13
- ODI0OTM1YzE1NGM1N2QwNzBiNzZlMzI1MTM1YjhkZDU0Nzc2OGU4Y2FkMTdi
14
- YTZmYjU3YjJiZjdkOGI5NWFmNDI4ZGNhMjk4NTZmM2VkYTYzZDg1MTc3NDQx
15
- NmYxZmM4YmM2ODg5MjhmYjgzNDEwZTk0ZTVmODZkMGM1YWVlMjQ=
6
+ metadata.gz: 61cffd95ae9374d1f09a6353785468d8b13db7a3fbb2e9936585d9b0f8092a34a6d683bb20032715465e7cb4e72afacd67fc80dd5cf6c6b1b01178658b67bc36
7
+ data.tar.gz: 9f2f90d90b7ec7a25b443da85dc89cb75912bf348e600175e5a83af9ed14699ab1a2313e463eda90bfbd3db87674e148bacdc11e0d275a5aa5c2928590fc4387
@@ -1,4 +1,6 @@
1
1
  language: ruby
2
2
  services:
3
3
  - mongodb
4
+ before_install:
5
+ - gem update bundler
4
6
  script: bundle exec rake spec:all
@@ -1,3 +1,10 @@
1
+ 0.4.0
2
+ ------
3
+ * (Sub)domain lookup is no longer case insensitive
4
+ * Added ability to use inverse_of (thx lowjoel)
5
+ * Added ability to disable tenant checking for a block (thx duboff)
6
+ * Allow for validation that associations belong to the tenant to reflect on associations which return an Array from `where` (thx ludamillion)
7
+
1
8
  0.3.9
2
9
  -----
3
10
  * Added ability to configure a default tenant for testing purposes. (thx iangreenleaf)
data/README.md CHANGED
@@ -83,6 +83,15 @@ any code in this block will be scoped to the current tenant. All methods that se
83
83
 
84
84
  **Note:** If the current tenant is not set by one of these methods, Acts_as_tenant will be unable to apply the proper scope to your models. So make sure you use one of the two methods to tell acts_as_tenant about the current tenant.
85
85
 
86
+ ### Disabling tenant checking for a block ###
87
+
88
+ ```ruby
89
+ ActsAsTenant.without_tenant do
90
+ # Tenant checking is disabled for all code in this block
91
+ end
92
+ ```
93
+ This is useful in shared routes such as admin panels or internal dashboards when `require_tenant` option is enabled throughout the app.
94
+
86
95
  ### Require tenant to be set always ###
87
96
 
88
97
  If you want to require the tenant to be set at all times, you can configure acts_as_tenant to raise an error when a query is made without a tenant available. See below under configuarion options.
@@ -151,7 +160,7 @@ acts_as_tenant(:account, :foreign_key => 'accountID) # by default AaT expects ac
151
160
  Configuration options
152
161
  ---------------------
153
162
  An initializer can be created to control (currently one) option in ActsAsTenant. Defaults
154
- are shown below with sample overrides following. In `config/initializer/acts_as_tenant.rb`:
163
+ are shown below with sample overrides following. In `config/initializers/acts_as_tenant.rb`:
155
164
 
156
165
  ```ruby
157
166
  ActsAsTenant.configure do |config|
@@ -165,7 +174,7 @@ Sidekiq support
165
174
  ---------------
166
175
 
167
176
  ActsAsTenant supports [Sidekiq](http://sidekiq.org/). A background processing library.
168
- Add the following code to your `config/initializer/acts_as_tenant.rb`:
177
+ Add the following code to your `config/initializers/acts_as_tenant.rb`:
169
178
 
170
179
  ```ruby
171
180
  require 'acts_as_tenant/sidekiq'
@@ -18,7 +18,9 @@ module ActsAsTenant
18
18
 
19
19
  private
20
20
  def find_tenant_by_subdomain
21
- ActsAsTenant.current_tenant = tenant_class.where(tenant_column => request.subdomains.last).first
21
+ if request.subdomains.last
22
+ ActsAsTenant.current_tenant = tenant_class.where(tenant_column => request.subdomains.last.downcase).first
23
+ end
22
24
  end
23
25
 
24
26
  def current_tenant
@@ -45,7 +47,11 @@ module ActsAsTenant
45
47
 
46
48
  private
47
49
  def find_tenant_by_subdomain_or_domain
48
- ActsAsTenant.current_tenant = tenant_class.where(tenant_primary_column => request.subdomains.last).first || tenant_class.where(tenant_second_column => request.domain).first
50
+ if request.subdomains.last
51
+ ActsAsTenant.current_tenant = tenant_class.where(tenant_primary_column => request.subdomains.last.downcase).first
52
+ else
53
+ ActsAsTenant.current_tenant = tenant_class.where(tenant_second_column => request.domain.downcase).first
54
+ end
49
55
  end
50
56
 
51
57
  def current_tenant
@@ -65,7 +71,7 @@ module ActsAsTenant
65
71
  def set_current_tenant(current_tenant_object)
66
72
  ActsAsTenant.current_tenant = current_tenant_object
67
73
  end
68
-
74
+
69
75
  def current_tenant
70
76
  ActsAsTenant.current_tenant
71
77
  end
@@ -21,6 +21,18 @@ module ActsAsTenant
21
21
  RequestStore.store[:current_tenant] || self.default_tenant
22
22
  end
23
23
 
24
+ def self.unscoped=(unscoped)
25
+ RequestStore.store[:acts_as_tenant_unscoped] = unscoped
26
+ end
27
+
28
+ def self.unscoped
29
+ RequestStore.store[:acts_as_tenant_unscoped]
30
+ end
31
+
32
+ def self.unscoped?
33
+ !!unscoped
34
+ end
35
+
24
36
  class << self
25
37
  attr_accessor :default_tenant
26
38
  end
@@ -39,6 +51,24 @@ module ActsAsTenant
39
51
  self.current_tenant = old_tenant
40
52
  end
41
53
 
54
+ def self.without_tenant(&block)
55
+ if block.nil?
56
+ raise ArgumentError, "block required"
57
+ end
58
+
59
+ old_tenant = current_tenant
60
+ old_unscoped = unscoped
61
+
62
+ self.current_tenant = nil
63
+ self.unscoped = true
64
+ value = block.call
65
+ return value
66
+
67
+ ensure
68
+ self.current_tenant = old_tenant
69
+ self.unscoped = old_unscoped
70
+ end
71
+
42
72
  module ModelExtensions
43
73
  def self.included(base)
44
74
  base.extend(ClassMethods)
@@ -49,18 +79,18 @@ module ActsAsTenant
49
79
  ActsAsTenant.set_tenant_klass(tenant)
50
80
 
51
81
  # Create the association
52
- valid_options = options.slice(:foreign_key, :class_name)
82
+ valid_options = options.slice(:foreign_key, :class_name, :inverse_of)
53
83
  fkey = valid_options[:foreign_key] || ActsAsTenant.fkey
54
84
  belongs_to tenant, valid_options
55
85
 
56
86
  default_scope lambda {
57
- if ActsAsTenant.configuration.require_tenant && ActsAsTenant.current_tenant.nil?
87
+ if ActsAsTenant.configuration.require_tenant && ActsAsTenant.current_tenant.nil? && !ActsAsTenant.unscoped?
58
88
  raise ActsAsTenant::Errors::NoTenantSet
59
89
  end
60
90
  if ActsAsTenant.current_tenant
61
91
  where(fkey.to_sym => ActsAsTenant.current_tenant.id)
62
92
  else
63
- all
93
+ Rails::VERSION::MAJOR < 4 ? scoped : all
64
94
  end
65
95
  }
66
96
 
@@ -87,7 +117,7 @@ module ActsAsTenant
87
117
  else
88
118
  a.primary_key
89
119
  end.to_sym
90
- record.errors.add attr, "association is invalid [ActsAsTenant]" unless value.nil? || association_class.where(primary_key => value).exists?
120
+ record.errors.add attr, "association is invalid [ActsAsTenant]" unless value.nil? || association_class.where(primary_key => value).any?
91
121
  end
92
122
  end
93
123
  end
@@ -1,3 +1,3 @@
1
1
  module ActsAsTenant
2
- VERSION = "0.3.9"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -282,17 +282,55 @@ describe ActsAsTenant do
282
282
  end
283
283
  end
284
284
 
285
+ describe "::without_tenant" do
286
+ it "should set current_tenant to nil inside the block" do
287
+ ActsAsTenant.without_tenant do
288
+ expect(ActsAsTenant.current_tenant).to be_nil
289
+ end
290
+ end
291
+
292
+ it "should reset current_tenant to the previous tenant once exiting the block" do
293
+ @account1 = Account.create!(:name => 'foo')
294
+
295
+ ActsAsTenant.current_tenant = @account1
296
+ ActsAsTenant.without_tenant do
297
+ end
298
+
299
+ expect(ActsAsTenant.current_tenant).to eq(@account1)
300
+ end
301
+
302
+ it "should return the value of the block" do
303
+ value = ActsAsTenant.without_tenant do
304
+ "something"
305
+ end
306
+
307
+ expect(value).to eq "something"
308
+ end
309
+
310
+ it "should raise an error when no block is provided" do
311
+ expect { ActsAsTenant.without_tenant }.to raise_error(ArgumentError, /block required/)
312
+ end
313
+ end
314
+
285
315
  # Tenant required
286
316
  context "tenant required" do
317
+ before do
318
+ @account1 = Account.create!(:name => 'foo')
319
+ @project1 = @account1.projects.create!(:name => 'foobar')
320
+ allow(ActsAsTenant.configuration).to receive_messages(require_tenant: true)
321
+ end
322
+
287
323
  describe "raises exception if no tenant specified" do
288
- before do
289
- @account1 = Account.create!(:name => 'foo')
290
- @project1 = @account1.projects.create!(:name => 'foobar')
291
- allow(ActsAsTenant.configuration).to receive_messages(require_tenant: true)
324
+ it "should raise an error when no tenant is provided" do
325
+ expect { Project.all }.to raise_error(ActsAsTenant::Errors::NoTenantSet)
292
326
  end
327
+ end
293
328
 
294
- it "should raise an error when no tenant is provided" do
295
- expect { Project.all.load }.to raise_error(ActsAsTenant::Errors::NoTenantSet)
329
+ describe "does not raise exception when run in unscoped mode" do
330
+ it "should not raise an error when no tenant is provided" do
331
+ expect do
332
+ ActsAsTenant.without_tenant { Project.all }
333
+ end.to_not raise_error
296
334
  end
297
335
  end
298
336
  end
@@ -18,7 +18,6 @@ describe ApplicationController, :type => :controller do
18
18
 
19
19
  it 'Finds the correct tenant with a example1.com' do
20
20
  @request.host = "example1.com"
21
- expect(Account).to receive(:where).with({subdomain: nil}) {[]}
22
21
  expect(Account).to receive(:where).with({domain: 'example1.com'}) {['account1']}
23
22
  get :index
24
23
  expect(ActsAsTenant.current_tenant).to eq 'account1'
@@ -38,5 +37,10 @@ describe ApplicationController, :type => :controller do
38
37
  expect(ActsAsTenant.current_tenant).to eq "account1"
39
38
  end
40
39
 
41
-
40
+ it 'Ignores case when finding tenant by subdomain' do
41
+ @request.host = "SubDomain.example.com"
42
+ expect(Account).to receive(:where).with({subdomain: 'subdomain'}) {['account1']}
43
+ get :index
44
+ expect(ActsAsTenant.current_tenant).to eq "account1"
45
+ end
42
46
  end
metadata CHANGED
@@ -1,111 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_tenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erwin Matthijssen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-29 00:00:00.000000000 Z
11
+ date: 2016-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: request_store
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.0.5
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.0.5
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ! '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '3.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ! '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec-rails
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ! '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: database_cleaner
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 1.3.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.3.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: sqlite3
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ! '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ! '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: mongoid
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: '4.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '4.0'
111
111
  - !ruby/object:Gem::Dependency
@@ -130,8 +130,8 @@ executables: []
130
130
  extensions: []
131
131
  extra_rdoc_files: []
132
132
  files:
133
- - .gitignore
134
- - .travis.yml
133
+ - ".gitignore"
134
+ - ".travis.yml"
135
135
  - CHANGELOG.md
136
136
  - Gemfile
137
137
  - MIT-LICENSE
@@ -168,17 +168,17 @@ require_paths:
168
168
  - lib
169
169
  required_ruby_version: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - ! '>='
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
173
  version: '0'
174
174
  required_rubygems_version: !ruby/object:Gem::Requirement
175
175
  requirements:
176
- - - ! '>='
176
+ - - ">="
177
177
  - !ruby/object:Gem::Version
178
178
  version: '0'
179
179
  requirements: []
180
180
  rubyforge_project: acts_as_tenant
181
- rubygems_version: 2.2.0
181
+ rubygems_version: 2.4.5.1
182
182
  signing_key:
183
183
  specification_version: 4
184
184
  summary: Add multi-tenancy to Rails applications using a shared db strategy