acts_as_tenant 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ 0.2.9
2
+ -----
3
+ * Added support for many-to-many associations (thx Nucleoid)
4
+
1
5
  0.2.8
2
6
  -----
3
7
  * Added dependencies to gemspec (thx aaronrenner)
@@ -1,117 +1,117 @@
1
- # ActsAsTenant
2
-
3
-
4
- module ActsAsTenant
5
-
6
- class << self
7
- cattr_accessor :tenant_class
8
-
9
- # This will also work whithin Fibers:
10
- # http://devblog.avdi.org/2012/02/02/ruby-thread-locals-are-also-fiber-local/
11
- def current_tenant=(tenant)
12
- Thread.current[:current_tenant] = tenant
13
- end
14
-
15
- def current_tenant
16
- Thread.current[:current_tenant]
17
- end
18
-
19
- # Sets the current_tenant within the given block
20
- def with_tenant(tenant, &block)
21
- if block.nil?
22
- raise ArgumentError, "block required"
23
- end
24
-
25
- old_tenant = self.current_tenant
26
- self.current_tenant = tenant
27
-
28
- block.call
29
-
30
- self.current_tenant= old_tenant
31
- end
32
- end
33
-
34
- module ModelExtensions
35
- extend ActiveSupport::Concern
36
-
37
- # Alias the v_uniqueness_of method so we can scope it to the current tenant when relevant
38
-
39
- module ClassMethods
40
-
41
- def acts_as_tenant(association = :account)
42
-
43
- # Method that enables checking if a class is scoped by tenant
44
- def self.is_scoped_by_tenant?
45
- true
46
- end
47
-
48
- ActsAsTenant.tenant_class ||= association
49
-
50
- # Setup the association between the class and the tenant class
51
- belongs_to association
52
-
53
- # get the tenant model and its foreign key
54
- reflection = reflect_on_association association
55
-
56
- # As the "foreign_key" method changed name in 3.1 we check for backward compatibility
57
- if reflection.respond_to?(:foreign_key)
58
- fkey = reflection.foreign_key
59
- else
60
- fkey = reflection.association_foreign_key
61
- end
62
-
63
- # set the current_tenant on newly created objects
64
- before_validation Proc.new {|m|
65
- return unless ActsAsTenant.current_tenant
66
- m.send "#{association}_id=".to_sym, ActsAsTenant.current_tenant.id
67
- }, :on => :create
68
-
69
- # set the default_scope to scope to current tenant
70
- default_scope lambda {
71
- where({fkey => ActsAsTenant.current_tenant.id}) if ActsAsTenant.current_tenant
72
- }
73
-
74
- # Rewrite accessors to make tenant foreign_key/association immutable
75
- define_method "#{fkey}=" do |integer|
76
- if new_record?
77
- write_attribute(fkey, integer)
78
- else
79
- raise "#{fkey} is immutable! [ActsAsTenant]"
80
- end
81
- end
82
-
83
- define_method "#{association}=" do |model|
84
- if new_record?
85
- super(model)
86
- else
87
- raise "#{association} is immutable! [ActsAsTenant]"
88
- end
89
- end
90
-
91
- # add validation of associations against tenant scope
92
- # we can't do this for polymorphic associations so we
93
- # exempt them
94
- reflect_on_all_associations.each do |a|
95
- unless a == reflection || a.macro == :has_many || a.macro == :has_one || a.options[:polymorphic]
96
- # check if the association is aliasing another class, if so
97
- # find the unaliased class name
98
- association_class = a.options[:class_name].nil? ? a.name.to_s.classify.constantize : a.options[:class_name].constantize
99
- validates_each a.foreign_key.to_sym do |record, attr, value|
100
- # Invalidate the association unless the parent is known to the tenant or no association has
101
- # been set.
102
- record.errors.add attr, "is invalid [ActsAsTenant]" unless value.nil? || association_class.where(:id => value).present?
103
- end
104
- end
105
- end
106
- end
107
-
108
- def validates_uniqueness_to_tenant(fields, args ={})
109
- raise "[ActsAsTenant] validates_uniqueness_to_tenant: no current tenant" unless respond_to?(:is_scoped_by_tenant?)
110
- tenant_id = lambda { "#{ActsAsTenant.tenant_class.to_s.downcase}_id"}.call
111
- args[:scope].nil? ? args[:scope] = tenant_id : args[:scope] << tenant_id
112
- validates_uniqueness_of(fields, args)
113
- end
114
-
115
- end
116
- end
117
- end
1
+ # ActsAsTenant
2
+
3
+
4
+ module ActsAsTenant
5
+
6
+ class << self
7
+ cattr_accessor :tenant_class
8
+
9
+ # This will also work whithin Fibers:
10
+ # http://devblog.avdi.org/2012/02/02/ruby-thread-locals-are-also-fiber-local/
11
+ def current_tenant=(tenant)
12
+ Thread.current[:current_tenant] = tenant
13
+ end
14
+
15
+ def current_tenant
16
+ Thread.current[:current_tenant]
17
+ end
18
+
19
+ # Sets the current_tenant within the given block
20
+ def with_tenant(tenant, &block)
21
+ if block.nil?
22
+ raise ArgumentError, "block required"
23
+ end
24
+
25
+ old_tenant = self.current_tenant
26
+ self.current_tenant = tenant
27
+
28
+ block.call
29
+
30
+ self.current_tenant= old_tenant
31
+ end
32
+ end
33
+
34
+ module ModelExtensions
35
+ extend ActiveSupport::Concern
36
+
37
+ # Alias the v_uniqueness_of method so we can scope it to the current tenant when relevant
38
+
39
+ module ClassMethods
40
+
41
+ def acts_as_tenant(association = :account)
42
+
43
+ # Method that enables checking if a class is scoped by tenant
44
+ def self.is_scoped_by_tenant?
45
+ true
46
+ end
47
+
48
+ ActsAsTenant.tenant_class ||= association
49
+
50
+ # Setup the association between the class and the tenant class
51
+ belongs_to association
52
+
53
+ # get the tenant model and its foreign key
54
+ reflection = reflect_on_association association
55
+
56
+ # As the "foreign_key" method changed name in 3.1 we check for backward compatibility
57
+ if reflection.respond_to?(:foreign_key)
58
+ fkey = reflection.foreign_key
59
+ else
60
+ fkey = reflection.association_foreign_key
61
+ end
62
+
63
+ # set the current_tenant on newly created objects
64
+ before_validation Proc.new {|m|
65
+ return unless ActsAsTenant.current_tenant
66
+ m.send "#{association}_id=".to_sym, ActsAsTenant.current_tenant.id
67
+ }, :on => :create
68
+
69
+ # set the default_scope to scope to current tenant
70
+ default_scope lambda {
71
+ where({fkey => ActsAsTenant.current_tenant.id}) if ActsAsTenant.current_tenant
72
+ }
73
+
74
+ # Rewrite accessors to make tenant foreign_key/association immutable
75
+ define_method "#{fkey}=" do |integer|
76
+ if new_record?
77
+ write_attribute(fkey, integer)
78
+ else
79
+ raise "#{fkey} is immutable! [ActsAsTenant]"
80
+ end
81
+ end
82
+
83
+ define_method "#{association}=" do |model|
84
+ if new_record?
85
+ super(model)
86
+ else
87
+ raise "#{association} is immutable! [ActsAsTenant]"
88
+ end
89
+ end
90
+
91
+ # add validation of associations against tenant scope
92
+ # we can't do this for polymorphic associations so we
93
+ # exempt them
94
+ reflect_on_all_associations.each do |a|
95
+ unless a == reflection || a.macro == :has_many || a.macro == :has_one || a.macro == :has_and_belongs_to_many || a.options[:polymorphic]
96
+ # check if the association is aliasing another class, if so
97
+ # find the unaliased class name
98
+ association_class = a.options[:class_name].nil? ? a.name.to_s.classify.constantize : a.options[:class_name].constantize
99
+ validates_each a.foreign_key.to_sym do |record, attr, value|
100
+ # Invalidate the association unless the parent is known to the tenant or no association has
101
+ # been set.
102
+ record.errors.add attr, "is invalid [ActsAsTenant]" unless value.nil? || association_class.where(:id => value).present?
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ def validates_uniqueness_to_tenant(fields, args ={})
109
+ raise "[ActsAsTenant] validates_uniqueness_to_tenant: no current tenant" unless respond_to?(:is_scoped_by_tenant?)
110
+ tenant_id = lambda { "#{ActsAsTenant.tenant_class.to_s.downcase}_id"}.call
111
+ args[:scope].nil? ? args[:scope] = tenant_id : args[:scope] << tenant_id
112
+ validates_uniqueness_of(fields, args)
113
+ end
114
+
115
+ end
116
+ end
117
+ end
@@ -1,3 +1,3 @@
1
1
  module ActsAsTenant
2
- VERSION = "0.2.8"
2
+ VERSION = "0.2.9"
3
3
  end
@@ -1,250 +1,298 @@
1
- require 'spec_helper'
2
-
3
- # Setup the db
4
- ActiveRecord::Schema.define(:version => 1) do
5
- create_table :accounts, :force => true do |t|
6
- t.column :name, :string
7
- end
8
-
9
- create_table :projects, :force => true do |t|
10
- t.column :name, :string
11
- t.column :account_id, :integer
12
- end
13
-
14
- create_table :managers, :force => true do |t|
15
- t.column :name, :string
16
- t.column :project_id, :integer
17
- t.column :account_id, :integer
18
- end
19
-
20
- create_table :tasks, :force => true do |t|
21
- t.column :name, :string
22
- t.column :account_id, :integer
23
- t.column :project_id, :integer
24
- t.column :completed, :boolean
25
- end
26
-
27
- create_table :countries, :force => true do |t|
28
- t.column :name, :string
29
- end
30
-
31
- create_table :cities, :force => true do |t|
32
- t.column :name, :string
33
- end
34
-
35
- create_table :sub_tasks, :force => true do |t|
36
- t.column :name, :string
37
- t.column :something_else, :integer
38
- end
39
-
40
- end
41
-
42
- # Setup the models
43
- class Account < ActiveRecord::Base
44
- has_many :projects
45
- end
46
-
47
- class Project < ActiveRecord::Base
48
- has_one :manager
49
- has_many :tasks
50
- acts_as_tenant :account
51
-
52
- validates_uniqueness_to_tenant :name
53
- end
54
-
55
- class Manager < ActiveRecord::Base
56
- belongs_to :project
57
- acts_as_tenant :account
58
- end
59
-
60
- class Task < ActiveRecord::Base
61
- belongs_to :project
62
- default_scope :conditions => { :completed => nil }, :order => "name"
63
-
64
- acts_as_tenant :account
65
- validates_uniqueness_of :name
66
- end
67
-
68
- class City < ActiveRecord::Base
69
- validates_uniqueness_of :name
70
- end
71
-
72
- class SubTask < ActiveRecord::Base
73
- acts_as_tenant :account
74
- belongs_to :something_else, :class_name => "Project"
75
- end
76
-
77
- # Start testing!
78
- describe ActsAsTenant do
79
- after { ActsAsTenant.current_tenant = nil }
80
-
81
- describe 'Setting the current tenant' do
82
- before { ActsAsTenant.current_tenant = :foo }
83
- it { ActsAsTenant.current_tenant == :foo }
84
- end
85
-
86
- describe 'is_scoped_as_tenant should return the correct value' do
87
- it {Project.respond_to?(:is_scoped_by_tenant?).should == true}
88
- end
89
-
90
- describe 'Project.all should be scoped to the current tenant if set' do
91
- before do
92
- @account1 = Account.create!(:name => 'foo')
93
- @account2 = Account.create!(:name => 'bar')
94
-
95
- @project1 = @account1.projects.create!(:name => 'foobar')
96
- @project2 = @account2.projects.create!(:name => 'baz')
97
-
98
- ActsAsTenant.current_tenant= @account1
99
- @projects = Project.all
100
- end
101
-
102
- it { @projects.length.should == 1 }
103
- it { @projects.should == [@project1] }
104
- end
105
-
106
- describe 'Project.unscoped.all should return the unscoped value' do
107
- before do
108
- @account1 = Account.create!(:name => 'foo')
109
- @account2 = Account.create!(:name => 'bar')
110
-
111
- @project1 = @account1.projects.create!(:name => 'foobar')
112
- @project2 = @account2.projects.create!(:name => 'baz')
113
-
114
- ActsAsTenant.current_tenant= @account1
115
- @projects = Project.unscoped.all
116
- end
117
-
118
- it { @projects.length.should == 2 }
119
- end
120
-
121
- describe 'Associations should be correctly scoped by current tenant' do
122
- before do
123
- @account = Account.create!(:name => 'foo')
124
- @project = @account.projects.create!(:name => 'foobar', :account_id => @account.id )
125
- # the next line would normally be nearly impossible: a task assigned to a tenant project,
126
- # but the task has no tenant assigned
127
- @task1 = Task.create!(:name => 'no_tenant', :project => @project)
128
-
129
- ActsAsTenant.current_tenant = @account
130
- @task2 = @project.tasks.create!(:name => 'baz')
131
- @tasks = @project.tasks
132
- end
133
-
134
- it 'should correctly set the tenant on the task created with current_tenant set' do
135
- @task2.account.should == @account
136
- end
137
-
138
- it 'should filter out the non-tenant task from the project' do
139
- @tasks.length.should == 1
140
- end
141
- end
142
-
143
- describe 'When dealing with a user defined default_scope' do
144
- before do
145
- @account = Account.create!(:name => 'foo')
146
- @project1 = Project.create!(:name => 'inaccessible')
147
- @task1 = Task.create!(:name => 'no_tenant', :project => @project1)
148
-
149
- ActsAsTenant.current_tenant = @account
150
- @project2 = Project.create!(:name => 'accessible')
151
- @task2 = @project2.tasks.create!(:name => 'bar')
152
- @task3 = @project2.tasks.create!(:name => 'baz')
153
- @task4 = @project2.tasks.create!(:name => 'foo')
154
- @task5 = @project2.tasks.create!(:name => 'foobar', :completed => true )
155
-
156
- @tasks= Task.all
157
- end
158
-
159
- it 'should apply both the tenant scope and the user defined default_scope, including :order' do
160
- @tasks.length.should == 3
161
- @tasks.should == [@task2, @task3, @task4]
162
- end
163
- end
164
-
165
- describe 'tenant_id should be immutable' do
166
- before do
167
- @account = Account.create!(:name => 'foo')
168
- @project = @account.projects.create!(:name => 'bar')
169
- end
170
-
171
- it { lambda {@project.account_id = @account.id + 1}.should raise_error }
172
- end
173
-
174
- describe 'Associations can only be made with in-scope objects' do
175
- before do
176
- @account = Account.create!(:name => 'foo')
177
- @project1 = Project.create!(:name => 'inaccessible_project', :account_id => @account.id + 1)
178
-
179
- ActsAsTenant.current_tenant = @account
180
- @project2 = Project.create!(:name => 'accessible_project')
181
- @task = @project2.tasks.create!(:name => 'bar')
182
- end
183
-
184
- it { @task.update_attributes(:project_id => @project1.id).should == false }
185
- end
186
-
187
- describe 'When using validates_uniqueness_to_tenant in a aat model' do
188
- before do
189
- @account = Account.create!(:name => 'foo')
190
- ActsAsTenant.current_tenant = @account
191
- @project1 = Project.create!(:name => 'bar')
192
- end
193
-
194
- it 'should not be possible to create a duplicate within the same tenant' do
195
- @project2 = Project.create(:name => 'bar').valid?.should == false
196
- end
197
-
198
- it 'should be possible to create a duplicate outside the tenant scope' do
199
- @account = Account.create!(:name => 'baz')
200
- ActsAsTenant.current_tenant = @account
201
- @project2 = Project.create(:name => 'bar').valid?.should == true
202
- end
203
- end
204
-
205
- describe 'When using validates_uniqueness_of in a NON-aat model' do
206
- before do
207
- @city1 = City.create!(:name => 'foo')
208
- end
209
- it 'should not be possible to create duplicates' do
210
- @city2 = City.create(:name => 'foo').valid?.should == false
211
- end
212
- end
213
-
214
- describe "It should be possible to use aliased associations" do
215
- it { @sub_task = SubTask.create(:name => 'foo').valid?.should == true }
216
- end
217
-
218
- describe "It should be possible to create and save an AaT-enabled child without it having a parent" do
219
- @account = Account.create!(:name => 'baz')
220
- ActsAsTenant.current_tenant = @account
221
- Task.create(:name => 'bar').valid?.should == true
222
- end
223
-
224
- describe "::with_tenant" do
225
- it "should set current_tenant to the specified tenant inside the block" do
226
- @account = Account.create!(:name => 'baz')
227
-
228
- ActsAsTenant.with_tenant(@account) do
229
- ActsAsTenant.current_tenant.should eq(@account)
230
- end
231
- end
232
-
233
-
234
- it "should return current_tenant to the previous tenant once exiting the block" do
235
- @account1 = Account.create!(:name => 'foo')
236
- @account2 = Account.create!(:name => 'bar')
237
-
238
- ActsAsTenant.current_tenant = @account1
239
- ActsAsTenant.with_tenant @account2 do
240
-
241
- end
242
-
243
- ActsAsTenant.current_tenant.should eq(@account1)
244
- end
245
-
246
- it "should raise an error when no block is provided" do
247
- expect { ActsAsTenant.with_tenant(nil) }.to raise_error(ArgumentError, /block required/)
248
- end
249
- end
250
- end
1
+ require 'spec_helper'
2
+
3
+ # Setup the db
4
+ ActiveRecord::Schema.define(:version => 2) do
5
+ create_table :accounts, :force => true do |t|
6
+ t.column :name, :string
7
+ end
8
+
9
+ create_table :projects, :force => true do |t|
10
+ t.column :name, :string
11
+ t.column :account_id, :integer
12
+ end
13
+
14
+ create_table :managers, :force => true do |t|
15
+ t.column :name, :string
16
+ t.column :project_id, :integer
17
+ t.column :account_id, :integer
18
+ end
19
+
20
+ create_table :tasks, :force => true do |t|
21
+ t.column :name, :string
22
+ t.column :account_id, :integer
23
+ t.column :project_id, :integer
24
+ t.column :completed, :boolean
25
+ end
26
+
27
+ create_table :countries, :force => true do |t|
28
+ t.column :name, :string
29
+ end
30
+
31
+ create_table :cities, :force => true do |t|
32
+ t.column :name, :string
33
+ end
34
+
35
+ create_table :sub_tasks, :force => true do |t|
36
+ t.column :name, :string
37
+ t.column :something_else, :integer
38
+ end
39
+
40
+ create_table :tools, :force => true do |t|
41
+ t.column :name, :string
42
+ t.column :account_id, :integer
43
+ end
44
+
45
+ create_table :managers_tools, {:force => true, id: false} do |t|
46
+ t.integer :manager_id
47
+ t.integer :tool_id
48
+ end
49
+
50
+ end
51
+
52
+ # Setup the models
53
+ class Account < ActiveRecord::Base
54
+ has_many :projects
55
+ end
56
+
57
+ class Project < ActiveRecord::Base
58
+ has_one :manager
59
+ has_many :tasks
60
+ acts_as_tenant :account
61
+
62
+ validates_uniqueness_to_tenant :name
63
+ end
64
+
65
+ class Manager < ActiveRecord::Base
66
+ belongs_to :project
67
+ has_and_belongs_to_many :tools
68
+
69
+ acts_as_tenant :account
70
+ end
71
+
72
+ class Task < ActiveRecord::Base
73
+ belongs_to :project
74
+ default_scope :conditions => { :completed => nil }, :order => "name"
75
+
76
+ acts_as_tenant :account
77
+ validates_uniqueness_of :name
78
+ end
79
+
80
+ class City < ActiveRecord::Base
81
+ validates_uniqueness_of :name
82
+ end
83
+
84
+ class SubTask < ActiveRecord::Base
85
+ acts_as_tenant :account
86
+ belongs_to :something_else, :class_name => "Project"
87
+ end
88
+
89
+ class Tool < ActiveRecord::Base
90
+ has_and_belongs_to_many :managers
91
+
92
+ acts_as_tenant :account
93
+ end
94
+
95
+ # Start testing!
96
+ describe ActsAsTenant do
97
+ after { ActsAsTenant.current_tenant = nil }
98
+
99
+ describe 'Setting the current tenant' do
100
+ before { ActsAsTenant.current_tenant = :foo }
101
+ it { ActsAsTenant.current_tenant == :foo }
102
+ end
103
+
104
+ describe 'is_scoped_as_tenant should return the correct value' do
105
+ it {Project.respond_to?(:is_scoped_by_tenant?).should == true}
106
+ end
107
+
108
+ describe 'Project.all should be scoped to the current tenant if set' do
109
+ before do
110
+ @account1 = Account.create!(:name => 'foo')
111
+ @account2 = Account.create!(:name => 'bar')
112
+
113
+ @project1 = @account1.projects.create!(:name => 'foobar')
114
+ @project2 = @account2.projects.create!(:name => 'baz')
115
+
116
+ ActsAsTenant.current_tenant= @account1
117
+ @projects = Project.all
118
+ end
119
+
120
+ it { @projects.length.should == 1 }
121
+ it { @projects.should == [@project1] }
122
+ end
123
+
124
+ describe 'Project.unscoped.all should return the unscoped value' do
125
+ before do
126
+ @account1 = Account.create!(:name => 'foo')
127
+ @account2 = Account.create!(:name => 'bar')
128
+
129
+ @project1 = @account1.projects.create!(:name => 'foobar')
130
+ @project2 = @account2.projects.create!(:name => 'baz')
131
+
132
+ ActsAsTenant.current_tenant= @account1
133
+ @projects = Project.unscoped.all
134
+ end
135
+
136
+ it { @projects.length.should == 2 }
137
+ end
138
+
139
+ describe 'Associations should be correctly scoped by current tenant' do
140
+ before do
141
+ @account = Account.create!(:name => 'foo')
142
+ @project = @account.projects.create!(:name => 'foobar', :account_id => @account.id )
143
+ # the next line would normally be nearly impossible: a task assigned to a tenant project,
144
+ # but the task has no tenant assigned
145
+ @task1 = Task.create!(:name => 'no_tenant', :project => @project)
146
+
147
+ ActsAsTenant.current_tenant = @account
148
+ @task2 = @project.tasks.create!(:name => 'baz')
149
+ @tasks = @project.tasks
150
+ end
151
+
152
+ it 'should correctly set the tenant on the task created with current_tenant set' do
153
+ @task2.account.should == @account
154
+ end
155
+
156
+ it 'should filter out the non-tenant task from the project' do
157
+ @tasks.length.should == 1
158
+ end
159
+ end
160
+
161
+ describe 'When dealing with a user defined default_scope' do
162
+ before do
163
+ @account = Account.create!(:name => 'foo')
164
+ @project1 = Project.create!(:name => 'inaccessible')
165
+ @task1 = Task.create!(:name => 'no_tenant', :project => @project1)
166
+
167
+ ActsAsTenant.current_tenant = @account
168
+ @project2 = Project.create!(:name => 'accessible')
169
+ @task2 = @project2.tasks.create!(:name => 'bar')
170
+ @task3 = @project2.tasks.create!(:name => 'baz')
171
+ @task4 = @project2.tasks.create!(:name => 'foo')
172
+ @task5 = @project2.tasks.create!(:name => 'foobar', :completed => true )
173
+
174
+ @tasks= Task.all
175
+ end
176
+
177
+ it 'should apply both the tenant scope and the user defined default_scope, including :order' do
178
+ @tasks.length.should == 3
179
+ @tasks.should == [@task2, @task3, @task4]
180
+ end
181
+ end
182
+
183
+ describe 'tenant_id should be immutable' do
184
+ before do
185
+ @account = Account.create!(:name => 'foo')
186
+ @project = @account.projects.create!(:name => 'bar')
187
+ end
188
+
189
+ it { lambda {@project.account_id = @account.id + 1}.should raise_error }
190
+ end
191
+
192
+ describe 'Associations can only be made with in-scope objects' do
193
+ before do
194
+ @account = Account.create!(:name => 'foo')
195
+ @project1 = Project.create!(:name => 'inaccessible_project', :account_id => @account.id + 1)
196
+
197
+ ActsAsTenant.current_tenant = @account
198
+ @project2 = Project.create!(:name => 'accessible_project')
199
+ @task = @project2.tasks.create!(:name => 'bar')
200
+ end
201
+
202
+ it { @task.update_attributes(:project_id => @project1.id).should == false }
203
+ end
204
+
205
+ describe 'When using validates_uniqueness_to_tenant in a aat model' do
206
+ before do
207
+ @account = Account.create!(:name => 'foo')
208
+ ActsAsTenant.current_tenant = @account
209
+ @project1 = Project.create!(:name => 'bar')
210
+ end
211
+
212
+ it 'should not be possible to create a duplicate within the same tenant' do
213
+ @project2 = Project.create(:name => 'bar').valid?.should == false
214
+ end
215
+
216
+ it 'should be possible to create a duplicate outside the tenant scope' do
217
+ @account = Account.create!(:name => 'baz')
218
+ ActsAsTenant.current_tenant = @account
219
+ @project2 = Project.create(:name => 'bar').valid?.should == true
220
+ end
221
+ end
222
+
223
+ describe 'When using validates_uniqueness_of in a NON-aat model' do
224
+ before do
225
+ @city1 = City.create!(:name => 'foo')
226
+ end
227
+ it 'should not be possible to create duplicates' do
228
+ @city2 = City.create(:name => 'foo').valid?.should == false
229
+ end
230
+ end
231
+
232
+ describe "It should be possible to use aliased associations" do
233
+ it { @sub_task = SubTask.create(:name => 'foo').valid?.should == true }
234
+ end
235
+
236
+ describe "It should be possible to create and save an AaT-enabled child without it having a parent" do
237
+ @account = Account.create!(:name => 'baz')
238
+ ActsAsTenant.current_tenant = @account
239
+ Task.create(:name => 'bar').valid?.should == true
240
+ end
241
+
242
+ describe "It should be possible to use direct many-to-many associations" do
243
+ @manager = Manager.create!(:name => 'fool')
244
+ @manager.tools.new(:name => 'golden hammer')
245
+ @manager.save.should == true
246
+ end
247
+
248
+ describe "It should be possible to use direct many-to-many associations" do
249
+ @manager = Manager.create!(:name => 'fool')
250
+ @manager.tools.new(:name => 'golden hammer')
251
+ @manager.save.should == true
252
+ end
253
+
254
+ describe "When using direct many-to-many associations they are correctly scoped to the tenant" do
255
+ before do
256
+ @account1 = Account.create!(:name => 'foo')
257
+ @account2 = Account.create!(:name => 'bar')
258
+
259
+ ActsAsTenant.current_tenant= @account1
260
+ @manager1 = Manager.create!(:name => 'fool')
261
+ @tool1 = @manager1.tools.create!(:name => 'golden hammer')
262
+
263
+ ActsAsTenant.current_tenant= @account2
264
+ @manager2 = Manager.create!(:name => 'pitty')
265
+ @tool2 = @manager2.tools.create!(:name => 'golden saw')
266
+
267
+ @tools = Tool.all
268
+ end
269
+ it { @tools.should == [@tool2] }
270
+ end
271
+
272
+ describe "::with_tenant" do
273
+ it "should set current_tenant to the specified tenant inside the block" do
274
+ @account = Account.create!(:name => 'baz')
275
+
276
+ ActsAsTenant.with_tenant(@account) do
277
+ ActsAsTenant.current_tenant.should eq(@account)
278
+ end
279
+ end
280
+
281
+
282
+ it "should return current_tenant to the previous tenant once exiting the block" do
283
+ @account1 = Account.create!(:name => 'foo')
284
+ @account2 = Account.create!(:name => 'bar')
285
+
286
+ ActsAsTenant.current_tenant = @account1
287
+ ActsAsTenant.with_tenant @account2 do
288
+
289
+ end
290
+
291
+ ActsAsTenant.current_tenant.should eq(@account1)
292
+ end
293
+
294
+ it "should raise an error when no block is provided" do
295
+ expect { ActsAsTenant.with_tenant(nil) }.to raise_error(ArgumentError, /block required/)
296
+ end
297
+ end
298
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_tenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-11-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &70247831625340 !ruby/object:Gem::Requirement
16
+ requirement: &70124434956940 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70247831625340
24
+ version_requirements: *70124434956940
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70247831624140 !ruby/object:Gem::Requirement
27
+ requirement: &70124434955660 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70247831624140
35
+ version_requirements: *70124434955660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: database_cleaner
38
- requirement: &70247831623580 !ruby/object:Gem::Requirement
38
+ requirement: &70124434955020 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70247831623580
46
+ version_requirements: *70124434955020
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sqlite3
49
- requirement: &70247831622820 !ruby/object:Gem::Requirement
49
+ requirement: &70124434954400 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70247831622820
57
+ version_requirements: *70124434954400
58
58
  description: Integrates multi-tenancy into a Rails application in a convenient and
59
59
  out-of-your way manner
60
60
  email: