acts_as_tenant 0.3.1 → 0.3.2
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 +13 -5
- data/CHANGELOG.md +6 -0
- data/README.md +2 -0
- data/Rakefile +4 -0
- data/acts_as_tenant.gemspec +1 -0
- data/lib/acts_as_tenant/controller_extensions.rb +1 -1
- data/lib/acts_as_tenant/model_extensions.rb +9 -7
- data/lib/acts_as_tenant/version.rb +1 -1
- data/spec/acts_as_tenant/model_extensions_spec.rb +13 -2
- data/spec/acts_as_tenant/tenant_by_filter_spec.rb +33 -0
- data/spec/acts_as_tenant/tenant_by_subdomain_spec.rb +32 -0
- data/spec/spec_helper.rb +12 -1
- metadata +35 -17
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTdlZmJkZjFiNWQ5YzUxNDM0OWJiOWEzYWMzZTIzZWM3ZmMzN2RmOA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTViNTg4MDVkYjIwYmY4Y2VlZWY0NGVkNmE2MzEzNjk2ODE5YjEwOA==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzZlMWJmNzAyZGQ2NDUwYWFmYjIzN2Q3YjliZDhlMjA4NGVjNzcwMGE4Yzc1
|
10
|
+
MzRmOGZmNTE0Yzk3NTY3YTI5ZTU2ZTBhNDczYTlmZjU0Y2JjYWY1MDM5ODE5
|
11
|
+
NTNhODA2ZjczYzk4Y2VkZjg4MDhmYTNlMDc5Y2UzZjgyNzBmZDA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjM2NzliNjViYjlkNjQyNjdmODNiMWY2MGFkODQ1ZjJiODQ1YjRjMzJkOWM2
|
14
|
+
MGFjNjJkNWVhNDkxMTE1NGZmZGIwZDM2ODA0ZWE3MmM0ZDQxMGNmYTcwMTVh
|
15
|
+
YzM3OWU5ZjUyYTJmZmExYTEyMDFiY2YyZmIzZThhYzhlMGYxNzI=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
0.3.2
|
2
|
+
-----
|
3
|
+
* correctly support nested models with has_many :through (thx dexion)
|
4
|
+
* Support 'www.subdomain.example.com' (thx wtfiwtz)
|
5
|
+
* Support setting `tenant_id` on scoped models if the `tenant_id` is nil (thx Matt Wilson)
|
6
|
+
|
1
7
|
0.3.1
|
2
8
|
-----
|
3
9
|
* Added support for Rails 4
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
Acts As Tenant
|
2
2
|
==============
|
3
3
|
|
4
|
+
[](https://travis-ci.org/ErwinM/acts_as_tenant)
|
5
|
+
|
4
6
|
**Note**: acts_as_tenant was introduced in this [blog post](http://www.rollcallapp.com/blog/2011/10/03/adding-multi-tenancy-to-your-rails-app-acts-as-tenant).
|
5
7
|
|
6
8
|
This gem was born out of our own need for a fail-safe and out-of-the-way manner to add multi-tenancy to our Rails app through a shared database strategy, that integrates (near) seamless with Rails.
|
data/Rakefile
CHANGED
data/acts_as_tenant.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
#s.add_dependency('request_store', '>= 1.0.5')
|
25
25
|
|
26
26
|
s.add_development_dependency('rspec')
|
27
|
+
s.add_development_dependency('rspec-rails')
|
27
28
|
s.add_development_dependency('database_cleaner')
|
28
29
|
s.add_development_dependency('sqlite3')
|
29
30
|
s.add_development_dependency('debugger')
|
@@ -18,7 +18,7 @@ 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.
|
21
|
+
ActsAsTenant.current_tenant = tenant_class.where(tenant_column => request.subdomains.last).first
|
22
22
|
end
|
23
23
|
|
24
24
|
def current_tenant
|
@@ -29,8 +29,10 @@ module ActsAsTenant
|
|
29
29
|
old_tenant = self.current_tenant
|
30
30
|
self.current_tenant = tenant
|
31
31
|
value = block.call
|
32
|
-
self.current_tenant = old_tenant
|
33
32
|
return value
|
33
|
+
|
34
|
+
ensure
|
35
|
+
self.current_tenant = old_tenant
|
34
36
|
end
|
35
37
|
|
36
38
|
module ModelExtensions
|
@@ -47,7 +49,7 @@ module ActsAsTenant
|
|
47
49
|
if ActsAsTenant.configuration.require_tenant && ActsAsTenant.current_tenant.nil?
|
48
50
|
raise ActsAsTenant::Errors::NoTenantSet
|
49
51
|
end
|
50
|
-
where({ActsAsTenant.fkey
|
52
|
+
where("#{self.table_name}.#{ActsAsTenant.fkey} = ?", ActsAsTenant.current_tenant.id) if ActsAsTenant.current_tenant
|
51
53
|
}
|
52
54
|
|
53
55
|
# Add the following validations to the receiving model:
|
@@ -74,13 +76,13 @@ module ActsAsTenant
|
|
74
76
|
# - Add a helper method to verify if a model has been scoped by AaT
|
75
77
|
#
|
76
78
|
define_method "#{ActsAsTenant.fkey}=" do |integer|
|
77
|
-
raise ActsAsTenant::Errors::TenantIsImmutable unless new_record?
|
78
|
-
write_attribute("#{ActsAsTenant.fkey}", integer)
|
79
|
+
raise ActsAsTenant::Errors::TenantIsImmutable unless new_record? || send(ActsAsTenant.fkey).nil?
|
80
|
+
write_attribute("#{ActsAsTenant.fkey}", integer)
|
79
81
|
end
|
80
82
|
|
81
|
-
define_method "#{ActsAsTenant.tenant_klass.to_s}=" do |model|
|
82
|
-
raise ActsAsTenant::Errors::TenantIsImmutable unless new_record?
|
83
|
-
super(model)
|
83
|
+
define_method "#{ActsAsTenant.tenant_klass.to_s}=" do |model|
|
84
|
+
raise ActsAsTenant::Errors::TenantIsImmutable unless new_record? || send(ActsAsTenant.fkey).nil?
|
85
|
+
super(model)
|
84
86
|
end
|
85
87
|
|
86
88
|
def scoped_by_tenant?
|
@@ -4,6 +4,7 @@ require 'spec_helper'
|
|
4
4
|
ActiveRecord::Schema.define(:version => 1) do
|
5
5
|
create_table :accounts, :force => true do |t|
|
6
6
|
t.column :name, :string
|
7
|
+
t.column :subdomain, :string
|
7
8
|
end
|
8
9
|
|
9
10
|
create_table :projects, :force => true do |t|
|
@@ -165,7 +166,7 @@ describe ActsAsTenant do
|
|
165
166
|
end
|
166
167
|
end
|
167
168
|
|
168
|
-
describe 'tenant_id should be immutable' do
|
169
|
+
describe 'tenant_id should be immutable, if already set' do
|
169
170
|
before do
|
170
171
|
@account = Account.create!(:name => 'foo')
|
171
172
|
@project = @account.projects.create!(:name => 'bar')
|
@@ -174,6 +175,16 @@ describe ActsAsTenant do
|
|
174
175
|
it { lambda {@project.account_id = @account.id + 1}.should raise_error }
|
175
176
|
end
|
176
177
|
|
178
|
+
describe 'tenant_id should be mutable, if not already set' do
|
179
|
+
before do
|
180
|
+
@account = Account.create!(:name => 'foo')
|
181
|
+
@project = Project.create!(:name => 'bar')
|
182
|
+
end
|
183
|
+
|
184
|
+
it { @project.account_id.should be_nil }
|
185
|
+
it { lambda { @project.account = @account }.should_not raise_error }
|
186
|
+
end
|
187
|
+
|
177
188
|
describe 'Associations can only be made with in-scope objects' do
|
178
189
|
before do
|
179
190
|
@account = Account.create!(:name => 'foo')
|
@@ -275,7 +286,7 @@ describe ActsAsTenant do
|
|
275
286
|
@project1 = @account1.projects.create!(:name => 'foobar')
|
276
287
|
ActsAsTenant.configuration.stub(require_tenant: true)
|
277
288
|
end
|
278
|
-
|
289
|
+
|
279
290
|
it "should raise an error when no tenant is provided" do
|
280
291
|
expect { Project.all.load }.to raise_error(ActsAsTenant::Errors::NoTenantSet)
|
281
292
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
#Setup test specific ApplicationController
|
4
|
+
class Account
|
5
|
+
attr_accessor :name
|
6
|
+
end
|
7
|
+
|
8
|
+
class ApplicationController2 < ActionController::Base
|
9
|
+
include Rails.application.routes.url_helpers
|
10
|
+
set_current_tenant_through_filter
|
11
|
+
before_filter :your_method_that_finds_the_current_tenant
|
12
|
+
|
13
|
+
def your_method_that_finds_the_current_tenant
|
14
|
+
current_account = Account.new
|
15
|
+
current_account.name = 'account1'
|
16
|
+
set_current_tenant(current_account)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# Start testing
|
22
|
+
describe ApplicationController2, :type => :controller do
|
23
|
+
controller do
|
24
|
+
def index
|
25
|
+
render :text => "custom called"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'Finds the correct tenant using the filter command' do
|
30
|
+
get :index
|
31
|
+
ActsAsTenant.current_tenant.name.should eq 'account1'
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
#Setup test specific ApplicationController
|
4
|
+
class Account; end # this is so the spec will work in isolation
|
5
|
+
|
6
|
+
class ApplicationController < ActionController::Base
|
7
|
+
include Rails.application.routes.url_helpers
|
8
|
+
set_current_tenant_by_subdomain
|
9
|
+
end
|
10
|
+
|
11
|
+
# Start testing
|
12
|
+
describe ApplicationController, :type => :controller do
|
13
|
+
controller do
|
14
|
+
def index
|
15
|
+
render :text => "custom called"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'Finds the correct tenant with a subdomain.example.com' do
|
20
|
+
@request.host = "account1.example.com"
|
21
|
+
Account.should_receive(:where).with({subdomain: 'account1'}) {['account1']}
|
22
|
+
get :index
|
23
|
+
ActsAsTenant.current_tenant.should eq 'account1'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'Finds the correct tenant with a www.subdomain.example.com' do
|
27
|
+
@request.host = "www.account1.example.com"
|
28
|
+
Account.should_receive(:where).with({subdomain: 'account1'}) {['account1']}
|
29
|
+
get :index
|
30
|
+
ActsAsTenant.current_tenant.should eq 'account1'
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,8 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
3
3
|
|
4
4
|
require 'database_cleaner'
|
5
5
|
require 'acts_as_tenant'
|
6
|
+
require 'rspec/rails'
|
7
|
+
require 'rails'
|
6
8
|
|
7
9
|
config = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'database.yml')))
|
8
10
|
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
|
@@ -22,5 +24,14 @@ RSpec.configure do |config|
|
|
22
24
|
DatabaseCleaner.clean
|
23
25
|
ActsAsTenant.current_tenant = nil
|
24
26
|
end
|
27
|
+
|
28
|
+
config.infer_base_class_for_anonymous_controllers = true
|
29
|
+
end
|
25
30
|
|
26
|
-
|
31
|
+
# Setup a test app
|
32
|
+
module Rollcall
|
33
|
+
class Application < Rails::Application; end
|
34
|
+
end
|
35
|
+
|
36
|
+
Rollcall::Application.config.secret_token = '1234567890123456789012345678901234567890'
|
37
|
+
Rollcall::Application.config.secret_key_base = '1234567890123456789012345678901234567890'
|
metadata
CHANGED
@@ -1,97 +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.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erwin Matthijssen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-04 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: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - '>='
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: database_cleaner
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- - '>='
|
73
|
+
- - ! '>='
|
60
74
|
- !ruby/object:Gem::Version
|
61
75
|
version: '0'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- - '>='
|
80
|
+
- - ! '>='
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: sqlite3
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- - '>='
|
87
|
+
- - ! '>='
|
74
88
|
- !ruby/object:Gem::Version
|
75
89
|
version: '0'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- - '>='
|
94
|
+
- - ! '>='
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: debugger
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- - '>='
|
101
|
+
- - ! '>='
|
88
102
|
- !ruby/object:Gem::Version
|
89
103
|
version: '0'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- - '>='
|
108
|
+
- - ! '>='
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
111
|
description: Integrates multi-tenancy into a Rails application in a convenient and
|
@@ -118,6 +132,8 @@ files:
|
|
118
132
|
- rails/init.rb
|
119
133
|
- spec/acts_as_tenant/configuration_spec.rb
|
120
134
|
- spec/acts_as_tenant/model_extensions_spec.rb
|
135
|
+
- spec/acts_as_tenant/tenant_by_filter_spec.rb
|
136
|
+
- spec/acts_as_tenant/tenant_by_subdomain_spec.rb
|
121
137
|
- spec/database.yml
|
122
138
|
- spec/spec_helper.rb
|
123
139
|
homepage: http://www.rollcallapp.com/blog
|
@@ -129,22 +145,24 @@ require_paths:
|
|
129
145
|
- lib
|
130
146
|
required_ruby_version: !ruby/object:Gem::Requirement
|
131
147
|
requirements:
|
132
|
-
- - '>='
|
148
|
+
- - ! '>='
|
133
149
|
- !ruby/object:Gem::Version
|
134
150
|
version: '0'
|
135
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
152
|
requirements:
|
137
|
-
- - '>='
|
153
|
+
- - ! '>='
|
138
154
|
- !ruby/object:Gem::Version
|
139
155
|
version: '0'
|
140
156
|
requirements: []
|
141
157
|
rubyforge_project: acts_as_tenant
|
142
|
-
rubygems_version: 2.0
|
158
|
+
rubygems_version: 2.2.0
|
143
159
|
signing_key:
|
144
160
|
specification_version: 4
|
145
161
|
summary: Add multi-tenancy to Rails applications using a shared db strategy
|
146
162
|
test_files:
|
147
163
|
- spec/acts_as_tenant/configuration_spec.rb
|
148
164
|
- spec/acts_as_tenant/model_extensions_spec.rb
|
165
|
+
- spec/acts_as_tenant/tenant_by_filter_spec.rb
|
166
|
+
- spec/acts_as_tenant/tenant_by_subdomain_spec.rb
|
149
167
|
- spec/database.yml
|
150
168
|
- spec/spec_helper.rb
|