tenancy 0.2.0 → 1.0.0
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 +4 -4
- data/.coveralls.yml +2 -0
- data/.rspec +2 -1
- data/.rvmrc +1 -1
- data/.travis.yml +5 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +13 -3
- data/README.md +57 -37
- data/Rakefile +4 -4
- data/gemfiles/active_record_32.gemfile +10 -4
- data/gemfiles/active_record_40.gemfile +10 -4
- data/gemfiles/mongoid_3.gemfile +12 -0
- data/gemfiles/mongoid_4.gemfile +12 -0
- data/lib/tenancy.rb +4 -2
- data/lib/tenancy/matchers.rb +29 -12
- data/lib/tenancy/resource.rb +2 -2
- data/lib/tenancy/resource_scope.rb +14 -51
- data/lib/tenancy/scoping.rb +13 -0
- data/lib/tenancy/scoping/active_record.rb +52 -0
- data/lib/tenancy/scoping/mongoid.rb +79 -0
- data/lib/tenancy/tenant.rb +13 -0
- data/lib/tenancy/version.rb +1 -1
- data/spec/lib/resource_spec.rb +82 -38
- data/spec/lib/scoping/active_record_spec.rb +135 -0
- data/spec/lib/scoping/mongoid_spec.rb +179 -0
- data/spec/lib/shoulda_matchers_spec.rb +39 -15
- data/spec/spec_helper.rb +57 -6
- data/spec/support/{models.rb → active_record/models.rb} +5 -5
- data/spec/support/{schema.rb → active_record/schema.rb} +3 -4
- data/spec/support/mongoid/connection.rb +3 -0
- data/spec/support/mongoid/models.rb +44 -0
- data/spec/support/mongoid/mongoid.yml +6 -0
- data/tenancy.gemspec +10 -13
- metadata +43 -97
- data/spec/lib/resource_scope_spec.rb +0 -125
@@ -3,65 +3,28 @@ module Tenancy
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
attr_reader :scope_fields
|
7
|
-
|
8
|
-
def scope_fields
|
9
|
-
@scope_fields ||= []
|
10
|
-
end
|
11
6
|
|
12
7
|
def scope_to(*resources)
|
13
|
-
|
14
|
-
raise ArgumentError, 'options should be blank if there are multiple resources' if resources.count > 1 and options.present?
|
15
|
-
|
16
|
-
resources.each do |resource|
|
17
|
-
resource = resource.to_sym
|
18
|
-
resource_class_name ||= (options[:class_name].to_s.presence || resource.to_s).classify
|
19
|
-
resource_class = resource_class_name.constantize
|
20
|
-
|
21
|
-
# validates and belongs_to
|
22
|
-
validates resource, presence: true
|
23
|
-
belongs_to resource, options
|
24
|
-
|
25
|
-
# default_scope
|
26
|
-
resource_foreign_key = reflect_on_association(resource).foreign_key
|
27
|
-
scope_fields << resource_foreign_key
|
28
|
-
default_scope { where(:"#{resource_foreign_key}" => resource_class.current_id) if resource_class.current_id }
|
29
|
-
|
30
|
-
# override to return current resource instance
|
31
|
-
# so that it doesn't touch db
|
32
|
-
define_method(resource) do |reload=false|
|
33
|
-
return super(reload) if reload
|
34
|
-
return resource_class.current if send(resource_foreign_key) == resource_class.current_id
|
35
|
-
super(reload)
|
36
|
-
end
|
37
|
-
end
|
8
|
+
tenancy_scoping.scope_to(resources)
|
38
9
|
end
|
39
10
|
|
40
|
-
|
41
|
-
|
42
|
-
scope = where(nil).with_default_scope
|
43
|
-
resources.each do |resource|
|
44
|
-
resource = resource.to_sym
|
45
|
-
reflection = reflect_on_association(resource)
|
46
|
-
next if reflection.nil?
|
47
|
-
|
48
|
-
resource_scope_sql = where(nil).table[reflection.foreign_key].eq(reflection.klass.current_id).to_sql
|
49
|
-
|
50
|
-
scope.where_values.delete_if { |query| query.to_sql == resource_scope_sql }
|
51
|
-
end
|
52
|
-
|
53
|
-
scope
|
11
|
+
def tenant_scope(*resources)
|
12
|
+
tenancy_scoping.tenant_scope(resources)
|
54
13
|
end
|
55
14
|
|
56
15
|
def validates_uniqueness_in_scope(fields, args={})
|
57
|
-
|
58
|
-
args[:scope] = Array.wrap(args[:scope]) << scope_fields
|
59
|
-
else
|
60
|
-
args[:scope] = scope_fields
|
61
|
-
end
|
62
|
-
|
63
|
-
validates_uniqueness_of(fields, args)
|
16
|
+
tenancy_scoping.validates_uniqueness_in_scope(fields, args)
|
64
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def tenancy_scoping
|
22
|
+
@tenancy_scoping ||= if defined?(::ActiveRecord) && ancestors.include?(::ActiveRecord::Base)
|
23
|
+
Scoping::ActiveRecord.new(self)
|
24
|
+
elsif defined?(Mongoid) && ancestors.include?(Mongoid::Document)
|
25
|
+
Scoping::Mongoid.new(self)
|
26
|
+
end
|
27
|
+
end
|
65
28
|
end
|
66
29
|
end
|
67
30
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Tenancy
|
2
|
+
class Scoping::ActiveRecord < Scoping
|
3
|
+
|
4
|
+
def scope_to(tenant_names)
|
5
|
+
options = tenant_names.extract_options!.dup
|
6
|
+
raise ArgumentError, "options should be blank if there are multiple tenants" if tenant_names.count > 1 and options.present?
|
7
|
+
|
8
|
+
tenant_names.each do |tenant_name|
|
9
|
+
# validates and belongs_to
|
10
|
+
klass.validates tenant_name, presence: true
|
11
|
+
klass.belongs_to tenant_name, options
|
12
|
+
|
13
|
+
tenant = Tenant.new(tenant_name, options[:class_name], klass)
|
14
|
+
self.tenants << tenant
|
15
|
+
|
16
|
+
# default_scope
|
17
|
+
klass.send(:default_scope, lambda { klass.where(:"#{tenant.foreign_key}" => tenant.klass.current_id) if tenant.klass.current_id })
|
18
|
+
|
19
|
+
# override to return current tenant instance
|
20
|
+
# so that it doesn"t touch db
|
21
|
+
klass.send(:define_method, tenant_name, lambda { |reload=false|
|
22
|
+
return super(reload) if reload
|
23
|
+
return tenant.klass.current if send(tenant.foreign_key) == tenant.klass.current_id
|
24
|
+
super(reload)
|
25
|
+
})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def tenant_scope(tenant_names)
|
30
|
+
scope = klass.where(nil).with_default_scope
|
31
|
+
tenants.each do |tenant|
|
32
|
+
next if tenant_names.include?(tenant.name.to_sym)
|
33
|
+
|
34
|
+
tenant_scope_sql = klass.where(nil).table[tenant.foreign_key].eq(tenant.klass.current_id).to_sql
|
35
|
+
scope.where_values.delete_if { |query| query.to_sql == tenant_scope_sql }
|
36
|
+
end
|
37
|
+
|
38
|
+
scope
|
39
|
+
end
|
40
|
+
|
41
|
+
def validates_uniqueness_in_scope(fields, args={})
|
42
|
+
foreign_keys = tenants.map(&:foreign_key)
|
43
|
+
if args[:scope]
|
44
|
+
args[:scope] = Array.wrap(args[:scope]) << foreign_keys
|
45
|
+
else
|
46
|
+
args[:scope] = foreign_keys
|
47
|
+
end
|
48
|
+
|
49
|
+
klass.validates_uniqueness_of(fields, args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Tenancy
|
2
|
+
class Scoping::Mongoid < Scoping
|
3
|
+
|
4
|
+
def scope_to(tenant_names)
|
5
|
+
options = tenant_names.extract_options!.dup
|
6
|
+
raise ArgumentError, "options should be blank if there are multiple tenants" if tenant_names.count > 1 and options.present?
|
7
|
+
|
8
|
+
tenant_names.each do |tenant_name|
|
9
|
+
# validates and belongs_to
|
10
|
+
klass.validates tenant_name, presence: true
|
11
|
+
klass.belongs_to tenant_name, options
|
12
|
+
|
13
|
+
tenant = Tenant.new(tenant_name, options[:class_name], klass)
|
14
|
+
self.tenants << tenant
|
15
|
+
|
16
|
+
# default_scope
|
17
|
+
klass.default_scope lambda {
|
18
|
+
if tenant.klass.current_id
|
19
|
+
klass.where(:"#{tenant.foreign_key}" => tenant.klass.current_id)
|
20
|
+
else
|
21
|
+
klass.where(nil)
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
# override to return current tenant_name instance
|
26
|
+
# so that it doesn't touch db
|
27
|
+
klass.send(:define_method, :"#{tenant_name}_with_tenant", lambda { |reload=false|
|
28
|
+
return send(:"#{tenant_name}_without_tenant", reload) if reload
|
29
|
+
return tenant.klass.current if send(tenant.foreign_key) == tenant.klass.current_id
|
30
|
+
send(:"#{tenant_name}_without_tenant", reload)
|
31
|
+
})
|
32
|
+
klass.alias_method_chain :"#{tenant_name}", :tenant
|
33
|
+
|
34
|
+
# override getter for mongoid 3.1
|
35
|
+
if ::Mongoid::VERSION.start_with?("3.1.")
|
36
|
+
klass.send(:define_method, tenant.foreign_key, lambda {
|
37
|
+
value = super()
|
38
|
+
if value.nil? && new_record?
|
39
|
+
self[tenant.foreign_key] = tenant.klass.current_id
|
40
|
+
end
|
41
|
+
self[tenant.foreign_key]
|
42
|
+
})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# tenants variable is for lambda
|
47
|
+
tenants = self.tenants
|
48
|
+
klass.send(:define_method, :shard_key_selector, lambda {
|
49
|
+
selector = super()
|
50
|
+
tenants.each do |tenant|
|
51
|
+
selector[tenant.foreign_key.to_s] = send(tenant.foreign_key) if tenant.klass.current_id
|
52
|
+
end
|
53
|
+
selector
|
54
|
+
})
|
55
|
+
end
|
56
|
+
|
57
|
+
def tenant_scope(tenant_names)
|
58
|
+
scope = klass.where(nil)
|
59
|
+
tenants.each do |tenant|
|
60
|
+
next if tenant_names.include?(tenant.name.to_sym)
|
61
|
+
|
62
|
+
scope.selector.delete(tenant.foreign_key.to_s)
|
63
|
+
end
|
64
|
+
|
65
|
+
scope
|
66
|
+
end
|
67
|
+
|
68
|
+
def validates_uniqueness_in_scope(fields, args={})
|
69
|
+
foreign_keys = tenants.map(&:foreign_key)
|
70
|
+
if args[:scope]
|
71
|
+
args[:scope] = Array.wrap(args[:scope]) << foreign_keys
|
72
|
+
else
|
73
|
+
args[:scope] = foreign_keys
|
74
|
+
end
|
75
|
+
|
76
|
+
klass.validates_uniqueness_of(fields, args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Tenancy
|
2
|
+
class Tenant
|
3
|
+
attr_accessor :name, :klass, :klass_name, :foreign_key
|
4
|
+
|
5
|
+
def initialize(name, klass_name, host_klass)
|
6
|
+
@name = name.to_sym
|
7
|
+
@klass_name = (klass_name.to_s.presence || name.to_s).classify
|
8
|
+
@klass = @klass_name.constantize
|
9
|
+
@foreign_key = host_klass.reflect_on_association(@name).foreign_key.to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
data/lib/tenancy/version.rb
CHANGED
data/spec/lib/resource_spec.rb
CHANGED
@@ -1,57 +1,101 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
3
|
+
if defined?(ActiveRecord)
|
4
|
+
describe "Tenancy::Resource" do
|
5
|
+
let(:camyp) { Portal.create(id: 1, domain_name: "yp.com.kh") }
|
6
|
+
let(:panpage) { Portal.create(id: 2, domain_name: "panpages.my") }
|
7
|
+
let(:yoolk) { Portal.create(id: 3, domain_name: "yoolk.com") }
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
9
|
+
it "set current with instance" do
|
10
|
+
Portal.current = camyp
|
13
11
|
|
14
|
-
|
12
|
+
Portal.current.should == camyp
|
13
|
+
RequestStore.store[:"Portal.current"].should == camyp
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
it "set current with id" do
|
17
|
+
Portal.current = panpage.id
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
Portal.current.should == panpage
|
20
|
+
RequestStore.store[:"Portal.current"].should == panpage
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
it "set current with nil" do
|
24
|
+
Portal.current = panpage
|
25
|
+
Portal.current = nil
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
Portal.current.should == nil
|
28
|
+
RequestStore.store[:"Portal.current"].should == nil
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
Portal.current = nil
|
31
|
+
it "#current_id" do
|
32
|
+
Portal.current = yoolk
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
end
|
34
|
+
Portal.current_id.should == yoolk.id
|
35
|
+
end
|
37
36
|
|
38
|
-
|
39
|
-
|
37
|
+
it "#with_scope with block" do
|
38
|
+
Portal.current.should == nil
|
40
39
|
|
41
|
-
|
40
|
+
Portal.with_tenant(yoolk) do
|
41
|
+
Portal.current.should == yoolk
|
42
|
+
end
|
43
|
+
|
44
|
+
Portal.current.should == nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "#with_scope without block" do
|
48
|
+
expect { Portal.with_tenant(yoolk) }.to raise_error(ArgumentError)
|
49
|
+
end
|
42
50
|
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if defined?(Mongoid)
|
54
|
+
describe "Tenancy::Resource" do
|
55
|
+
let(:camyp) { Mongo::Portal.create(domain_name: "yp.com.kh") }
|
56
|
+
let(:panpage) { Mongo::Portal.create(domain_name: "panpages.my") }
|
57
|
+
let(:yoolk) { Mongo::Portal.create(domain_name: "yoolk.com") }
|
43
58
|
|
44
|
-
|
45
|
-
|
59
|
+
it "set current with instance" do
|
60
|
+
Mongo::Portal.current = camyp
|
46
61
|
|
47
|
-
|
48
|
-
Portal.current.should ==
|
62
|
+
Mongo::Portal.current.should == camyp
|
63
|
+
RequestStore.store[:"Mongo::Portal.current"].should == camyp
|
49
64
|
end
|
50
65
|
|
51
|
-
|
52
|
-
|
66
|
+
it "set current with id" do
|
67
|
+
Mongo::Portal.current = panpage.id
|
68
|
+
|
69
|
+
Mongo::Portal.current.should == panpage
|
70
|
+
RequestStore.store[:"Mongo::Portal.current"].should == panpage
|
71
|
+
end
|
72
|
+
|
73
|
+
it "set current with nil" do
|
74
|
+
Mongo::Portal.current = panpage
|
75
|
+
Mongo::Portal.current = nil
|
76
|
+
|
77
|
+
Mongo::Portal.current.should == nil
|
78
|
+
RequestStore.store[:"Mongo::Portal.current"].should == nil
|
79
|
+
end
|
80
|
+
|
81
|
+
it "#current_id" do
|
82
|
+
Mongo::Portal.current = yoolk
|
53
83
|
|
54
|
-
|
55
|
-
|
84
|
+
Mongo::Portal.current_id.should == yoolk.id
|
85
|
+
end
|
86
|
+
|
87
|
+
it "#with_scope with block" do
|
88
|
+
Mongo::Portal.current.should == nil
|
89
|
+
|
90
|
+
Mongo::Portal.with_tenant(yoolk) do
|
91
|
+
Mongo::Portal.current.should == yoolk
|
92
|
+
end
|
93
|
+
|
94
|
+
Mongo::Portal.current.should == nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "#with_scope without block" do
|
98
|
+
expect { Mongo::Portal.with_tenant(yoolk) }.to raise_error(ArgumentError)
|
99
|
+
end
|
56
100
|
end
|
57
101
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
if defined?(ActiveRecord)
|
4
|
+
describe "Tenancy::Scoping::ActiveRecord" do
|
5
|
+
let(:camyp) { Portal.create(domain_name: "yp.com.kh") }
|
6
|
+
let(:panpages) { Portal.create(domain_name: "panpages.com") }
|
7
|
+
let(:listing) { Listing.create(name: "Listing 1", portal_id: camyp.id) }
|
8
|
+
|
9
|
+
describe Listing do
|
10
|
+
it { should belong_to(:portal) }
|
11
|
+
|
12
|
+
it { should validate_presence_of(:portal) }
|
13
|
+
|
14
|
+
it { should validate_uniqueness_of(:name).scoped_to(:portal_id).case_insensitive }
|
15
|
+
|
16
|
+
it "have default_scope with :portal_id field" do
|
17
|
+
Portal.current = camyp
|
18
|
+
|
19
|
+
expect(Listing.where(nil).to_sql).to eq(Listing.where(portal_id: Portal.current_id).to_sql)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "doesn't have default_scope when it doesn't have current portal" do
|
23
|
+
Portal.current = nil
|
24
|
+
|
25
|
+
expect(Listing.where(nil).to_sql).not_to include(%{"listings"."portal_id" = #{Portal.current_id}})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Communication do
|
30
|
+
it { should belong_to(:portal) }
|
31
|
+
|
32
|
+
it { should validate_presence_of(:portal) }
|
33
|
+
|
34
|
+
it { should belong_to(:listing) }
|
35
|
+
|
36
|
+
it { should validate_presence_of(:listing) }
|
37
|
+
|
38
|
+
it { should validate_uniqueness_of(:value).scoped_to(:portal_id, :listing_id) }
|
39
|
+
|
40
|
+
it "have default_scope with :portal_id and :listing_id" do
|
41
|
+
Portal.current = camyp
|
42
|
+
Listing.current = listing
|
43
|
+
|
44
|
+
Communication.where(nil).to_sql.should == Communication.where(portal_id: Portal.current_id, listing_id: Listing.current_id).to_sql
|
45
|
+
end
|
46
|
+
|
47
|
+
it "doesn't have default_scope when it doesn't have current portal and listing" do
|
48
|
+
Portal.current = nil
|
49
|
+
Listing.current = nil
|
50
|
+
|
51
|
+
expect(Communication.where(nil).to_sql).not_to include(%{"communications"."portal_id" = #{Portal.current_id}})
|
52
|
+
expect(Communication.where(nil).to_sql).not_to include(%{"communications"."listing_id" = #{Listing.current_id}})
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ExtraCommunication do
|
57
|
+
it { should belong_to(:portal) }
|
58
|
+
|
59
|
+
it { should belong_to(:listing) }
|
60
|
+
|
61
|
+
it "raise exception when passing two resources and options" do
|
62
|
+
expect { ExtraCommunication.scope_to(:portal, :listing, class_name: "Listing") }.to raise_error(ArgumentError)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "uses the correct scope" do
|
66
|
+
listing2 = Listing.create(name: "Name 2", portal: camyp)
|
67
|
+
|
68
|
+
Portal.current = camyp
|
69
|
+
Listing.current = listing2
|
70
|
+
|
71
|
+
extra_communication = ExtraCommunication.new
|
72
|
+
expect(extra_communication.listing_id).to eq(listing2.id)
|
73
|
+
expect(extra_communication.portal_id).to eq(camyp.id)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "belongs_to method override" do
|
78
|
+
before(:each) { Portal.current = camyp }
|
79
|
+
|
80
|
+
it "reload belongs_to when passes true" do
|
81
|
+
listing.portal.domain_name = "abc.com"
|
82
|
+
expect(listing.portal(true).object_id).not_to eq(Portal.current.object_id)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "doesn't reload belongs_to" do
|
86
|
+
listing.portal.domain_name = "abc.com"
|
87
|
+
expect(listing.portal.object_id).to eq(Portal.current.object_id)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "returns different object" do
|
91
|
+
listing.portal_id = panpages.id
|
92
|
+
expect(listing.portal.object_id).not_to eq(Portal.current.object_id)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "doesn't touch db" do
|
96
|
+
current_listing = listing
|
97
|
+
|
98
|
+
Portal.establish_connection(adapter: "sqlite3", database: "spec/invalid.sqlite3")
|
99
|
+
expect(current_listing.portal.object_id).to eq(Portal.current.object_id)
|
100
|
+
|
101
|
+
Portal.establish_connection(ActiveRecord::Base.connection_config)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#tenant_scope" do
|
106
|
+
before(:each) { Portal.current = camyp }
|
107
|
+
|
108
|
+
it "scopes only :current_portal" do
|
109
|
+
Listing.current = listing
|
110
|
+
|
111
|
+
expect(Communication.tenant_scope(:portal).to_sql).not_to include(%{"communications"."listing_id" = #{Listing.current_id}})
|
112
|
+
expect(Communication.tenant_scope(:portal).to_sql).to eq(%{SELECT "communications".* FROM "communications" WHERE "communications"."is_active" = 't' AND "communications"."portal_id" = #{Portal.current_id}})
|
113
|
+
end
|
114
|
+
|
115
|
+
it "scopes only :current_listing" do
|
116
|
+
Listing.current = listing
|
117
|
+
|
118
|
+
expect(Communication.tenant_scope(:listing).to_sql).not_to include(%{"communications"."portal_id" = #{Portal.current_id}})
|
119
|
+
expect(Communication.tenant_scope(:listing).to_sql).to eq(%{SELECT "communications".* FROM "communications" WHERE "communications"."is_active" = 't' AND "communications"."listing_id" = #{Listing.current_id}})
|
120
|
+
end
|
121
|
+
|
122
|
+
it "scopes only :current_listing and :current_portal" do
|
123
|
+
Listing.current = listing
|
124
|
+
|
125
|
+
expect(Communication.tenant_scope(:listing, :portal).to_sql).to eq(Communication.where(nil).to_sql)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "scopes nothing" do
|
129
|
+
Listing.current = listing
|
130
|
+
|
131
|
+
expect(Communication.tenant_scope(nil).to_sql).to eq(%{SELECT "communications".* FROM "communications" WHERE "communications"."is_active" = 't'})
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|