acts_as_tenant 0.2.8 → 0.2.9

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.
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: