activerecord-multi-tenant 0.2.1 → 0.3.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/.gitignore +2 -0
- data/Appraisals +12 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +151 -0
- data/README.md +88 -0
- data/Rakefile +7 -0
- data/activerecord-multi-tenant.gemspec +25 -0
- data/docker-compose.yml +18 -0
- data/gemfiles/rails_3.2.gemfile +7 -0
- data/gemfiles/rails_3.2.gemfile.lock +97 -0
- data/gemfiles/rails_4.2.gemfile +6 -0
- data/gemfiles/rails_4.2.gemfile.lock +110 -0
- data/gemfiles/rails_5.0.gemfile +6 -0
- data/gemfiles/rails_5.0.gemfile.lock +115 -0
- data/lib/activerecord-multi-tenant.rb +2 -0
- data/lib/activerecord-multi-tenant/controller_extensions.rb +22 -0
- data/lib/activerecord-multi-tenant/default_scope.rb +1 -1
- data/lib/activerecord-multi-tenant/migrations.rb +1 -1
- data/lib/activerecord-multi-tenant/model_extensions.rb +120 -0
- data/lib/activerecord-multi-tenant/multi_tenant.rb +33 -44
- data/lib/activerecord-multi-tenant/version.rb +1 -1
- data/spec/activerecord-multi-tenant/controller_extensions_spec.rb +30 -0
- data/spec/activerecord-multi-tenant/model_extensions_spec.rb +153 -0
- data/spec/activerecord-multi-tenant/record_callback_spec.rb +22 -0
- data/spec/activerecord-multi-tenant/record_finding_spec.rb +11 -0
- data/spec/activerecord-multi-tenant/record_modifications_spec.rb +20 -0
- data/spec/database.yml +9 -0
- data/spec/schema.rb +104 -0
- data/spec/spec_helper.rb +43 -0
- metadata +44 -5
@@ -0,0 +1,110 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (4.2.7.1)
|
5
|
+
actionpack (= 4.2.7.1)
|
6
|
+
actionview (= 4.2.7.1)
|
7
|
+
activejob (= 4.2.7.1)
|
8
|
+
mail (~> 2.5, >= 2.5.4)
|
9
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
10
|
+
actionpack (4.2.7.1)
|
11
|
+
actionview (= 4.2.7.1)
|
12
|
+
activesupport (= 4.2.7.1)
|
13
|
+
rack (~> 1.6)
|
14
|
+
rack-test (~> 0.6.2)
|
15
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
16
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
17
|
+
actionview (4.2.7.1)
|
18
|
+
activesupport (= 4.2.7.1)
|
19
|
+
builder (~> 3.1)
|
20
|
+
erubis (~> 2.7.0)
|
21
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
22
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
23
|
+
activejob (4.2.7.1)
|
24
|
+
activesupport (= 4.2.7.1)
|
25
|
+
globalid (>= 0.3.0)
|
26
|
+
activemodel (4.2.7.1)
|
27
|
+
activesupport (= 4.2.7.1)
|
28
|
+
builder (~> 3.1)
|
29
|
+
activerecord (4.2.7.1)
|
30
|
+
activemodel (= 4.2.7.1)
|
31
|
+
activesupport (= 4.2.7.1)
|
32
|
+
arel (~> 6.0)
|
33
|
+
activesupport (4.2.7.1)
|
34
|
+
i18n (~> 0.7)
|
35
|
+
json (~> 1.7, >= 1.7.7)
|
36
|
+
minitest (~> 5.1)
|
37
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
38
|
+
tzinfo (~> 1.1)
|
39
|
+
appraisal (2.1.0)
|
40
|
+
bundler
|
41
|
+
rake
|
42
|
+
thor (>= 0.14.0)
|
43
|
+
arel (6.0.4)
|
44
|
+
builder (3.2.2)
|
45
|
+
concurrent-ruby (1.0.4)
|
46
|
+
erubis (2.7.0)
|
47
|
+
globalid (0.3.7)
|
48
|
+
activesupport (>= 4.1.0)
|
49
|
+
i18n (0.7.0)
|
50
|
+
json (1.8.3)
|
51
|
+
loofah (2.0.3)
|
52
|
+
nokogiri (>= 1.5.9)
|
53
|
+
mail (2.6.4)
|
54
|
+
mime-types (>= 1.16, < 4)
|
55
|
+
mime-types (3.1)
|
56
|
+
mime-types-data (~> 3.2015)
|
57
|
+
mime-types-data (3.2016.0521)
|
58
|
+
mini_portile2 (2.1.0)
|
59
|
+
minitest (5.10.1)
|
60
|
+
nokogiri (1.7.0)
|
61
|
+
mini_portile2 (~> 2.1.0)
|
62
|
+
rack (1.6.5)
|
63
|
+
rack-test (0.6.3)
|
64
|
+
rack (>= 1.0)
|
65
|
+
rails (4.2.7.1)
|
66
|
+
actionmailer (= 4.2.7.1)
|
67
|
+
actionpack (= 4.2.7.1)
|
68
|
+
actionview (= 4.2.7.1)
|
69
|
+
activejob (= 4.2.7.1)
|
70
|
+
activemodel (= 4.2.7.1)
|
71
|
+
activerecord (= 4.2.7.1)
|
72
|
+
activesupport (= 4.2.7.1)
|
73
|
+
bundler (>= 1.3.0, < 2.0)
|
74
|
+
railties (= 4.2.7.1)
|
75
|
+
sprockets-rails
|
76
|
+
rails-deprecated_sanitizer (1.0.3)
|
77
|
+
activesupport (>= 4.2.0.alpha)
|
78
|
+
rails-dom-testing (1.0.8)
|
79
|
+
activesupport (>= 4.2.0.beta, < 5.0)
|
80
|
+
nokogiri (~> 1.6)
|
81
|
+
rails-deprecated_sanitizer (>= 1.0.1)
|
82
|
+
rails-html-sanitizer (1.0.3)
|
83
|
+
loofah (~> 2.0)
|
84
|
+
railties (4.2.7.1)
|
85
|
+
actionpack (= 4.2.7.1)
|
86
|
+
activesupport (= 4.2.7.1)
|
87
|
+
rake (>= 0.8.7)
|
88
|
+
thor (>= 0.18.1, < 2.0)
|
89
|
+
rake (12.0.0)
|
90
|
+
sprockets (3.7.1)
|
91
|
+
concurrent-ruby (~> 1.0)
|
92
|
+
rack (> 1, < 3)
|
93
|
+
sprockets-rails (3.2.0)
|
94
|
+
actionpack (>= 4.0)
|
95
|
+
activesupport (>= 4.0)
|
96
|
+
sprockets (>= 3.0.0)
|
97
|
+
thor (0.19.4)
|
98
|
+
thread_safe (0.3.5)
|
99
|
+
tzinfo (1.2.2)
|
100
|
+
thread_safe (~> 0.1)
|
101
|
+
|
102
|
+
PLATFORMS
|
103
|
+
ruby
|
104
|
+
|
105
|
+
DEPENDENCIES
|
106
|
+
appraisal
|
107
|
+
rails (= 4.2.7.1)
|
108
|
+
|
109
|
+
BUNDLED WITH
|
110
|
+
1.11.2
|
@@ -0,0 +1,115 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actioncable (5.0.1)
|
5
|
+
actionpack (= 5.0.1)
|
6
|
+
nio4r (~> 1.2)
|
7
|
+
websocket-driver (~> 0.6.1)
|
8
|
+
actionmailer (5.0.1)
|
9
|
+
actionpack (= 5.0.1)
|
10
|
+
actionview (= 5.0.1)
|
11
|
+
activejob (= 5.0.1)
|
12
|
+
mail (~> 2.5, >= 2.5.4)
|
13
|
+
rails-dom-testing (~> 2.0)
|
14
|
+
actionpack (5.0.1)
|
15
|
+
actionview (= 5.0.1)
|
16
|
+
activesupport (= 5.0.1)
|
17
|
+
rack (~> 2.0)
|
18
|
+
rack-test (~> 0.6.3)
|
19
|
+
rails-dom-testing (~> 2.0)
|
20
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
21
|
+
actionview (5.0.1)
|
22
|
+
activesupport (= 5.0.1)
|
23
|
+
builder (~> 3.1)
|
24
|
+
erubis (~> 2.7.0)
|
25
|
+
rails-dom-testing (~> 2.0)
|
26
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
27
|
+
activejob (5.0.1)
|
28
|
+
activesupport (= 5.0.1)
|
29
|
+
globalid (>= 0.3.6)
|
30
|
+
activemodel (5.0.1)
|
31
|
+
activesupport (= 5.0.1)
|
32
|
+
activerecord (5.0.1)
|
33
|
+
activemodel (= 5.0.1)
|
34
|
+
activesupport (= 5.0.1)
|
35
|
+
arel (~> 7.0)
|
36
|
+
activesupport (5.0.1)
|
37
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
38
|
+
i18n (~> 0.7)
|
39
|
+
minitest (~> 5.1)
|
40
|
+
tzinfo (~> 1.1)
|
41
|
+
appraisal (2.1.0)
|
42
|
+
bundler
|
43
|
+
rake
|
44
|
+
thor (>= 0.14.0)
|
45
|
+
arel (7.1.4)
|
46
|
+
builder (3.2.2)
|
47
|
+
concurrent-ruby (1.0.4)
|
48
|
+
erubis (2.7.0)
|
49
|
+
globalid (0.3.7)
|
50
|
+
activesupport (>= 4.1.0)
|
51
|
+
i18n (0.7.0)
|
52
|
+
loofah (2.0.3)
|
53
|
+
nokogiri (>= 1.5.9)
|
54
|
+
mail (2.6.4)
|
55
|
+
mime-types (>= 1.16, < 4)
|
56
|
+
method_source (0.8.2)
|
57
|
+
mime-types (3.1)
|
58
|
+
mime-types-data (~> 3.2015)
|
59
|
+
mime-types-data (3.2016.0521)
|
60
|
+
mini_portile2 (2.1.0)
|
61
|
+
minitest (5.10.1)
|
62
|
+
nio4r (1.2.1)
|
63
|
+
nokogiri (1.7.0)
|
64
|
+
mini_portile2 (~> 2.1.0)
|
65
|
+
rack (2.0.1)
|
66
|
+
rack-test (0.6.3)
|
67
|
+
rack (>= 1.0)
|
68
|
+
rails (5.0.1)
|
69
|
+
actioncable (= 5.0.1)
|
70
|
+
actionmailer (= 5.0.1)
|
71
|
+
actionpack (= 5.0.1)
|
72
|
+
actionview (= 5.0.1)
|
73
|
+
activejob (= 5.0.1)
|
74
|
+
activemodel (= 5.0.1)
|
75
|
+
activerecord (= 5.0.1)
|
76
|
+
activesupport (= 5.0.1)
|
77
|
+
bundler (>= 1.3.0, < 2.0)
|
78
|
+
railties (= 5.0.1)
|
79
|
+
sprockets-rails (>= 2.0.0)
|
80
|
+
rails-dom-testing (2.0.2)
|
81
|
+
activesupport (>= 4.2.0, < 6.0)
|
82
|
+
nokogiri (~> 1.6)
|
83
|
+
rails-html-sanitizer (1.0.3)
|
84
|
+
loofah (~> 2.0)
|
85
|
+
railties (5.0.1)
|
86
|
+
actionpack (= 5.0.1)
|
87
|
+
activesupport (= 5.0.1)
|
88
|
+
method_source
|
89
|
+
rake (>= 0.8.7)
|
90
|
+
thor (>= 0.18.1, < 2.0)
|
91
|
+
rake (12.0.0)
|
92
|
+
sprockets (3.7.1)
|
93
|
+
concurrent-ruby (~> 1.0)
|
94
|
+
rack (> 1, < 3)
|
95
|
+
sprockets-rails (3.2.0)
|
96
|
+
actionpack (>= 4.0)
|
97
|
+
activesupport (>= 4.0)
|
98
|
+
sprockets (>= 3.0.0)
|
99
|
+
thor (0.19.4)
|
100
|
+
thread_safe (0.3.5)
|
101
|
+
tzinfo (1.2.2)
|
102
|
+
thread_safe (~> 0.1)
|
103
|
+
websocket-driver (0.6.4)
|
104
|
+
websocket-extensions (>= 0.1.0)
|
105
|
+
websocket-extensions (0.1.2)
|
106
|
+
|
107
|
+
PLATFORMS
|
108
|
+
ruby
|
109
|
+
|
110
|
+
DEPENDENCIES
|
111
|
+
appraisal
|
112
|
+
rails (= 5.0.1)
|
113
|
+
|
114
|
+
BUNDLED WITH
|
115
|
+
1.11.2
|
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'activerecord-multi-tenant/controller_extensions'
|
1
2
|
require 'activerecord-multi-tenant/copy_from_client'
|
2
3
|
require 'activerecord-multi-tenant/default_scope'
|
3
4
|
require 'activerecord-multi-tenant/migrations'
|
5
|
+
require 'activerecord-multi-tenant/model_extensions'
|
4
6
|
require 'activerecord-multi-tenant/multi_tenant'
|
5
7
|
require 'activerecord-multi-tenant/referential_integrity'
|
6
8
|
require 'activerecord-multi-tenant/version'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module MultiTenant
|
2
|
+
module ControllerExtensions
|
3
|
+
def set_current_tenant_through_filter
|
4
|
+
self.class_eval do
|
5
|
+
helper_method :current_tenant
|
6
|
+
|
7
|
+
private
|
8
|
+
def set_current_tenant(current_tenant_object)
|
9
|
+
MultiTenant.current_tenant = current_tenant_object
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_tenant
|
13
|
+
MultiTenant.current_tenant
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if defined?(ActionController::Base)
|
21
|
+
ActionController::Base.extend MultiTenant::ControllerExtensions
|
22
|
+
end
|
@@ -3,7 +3,7 @@ class ActiveRecord::Base
|
|
3
3
|
alias :unscoped_orig :unscoped
|
4
4
|
def unscoped
|
5
5
|
if respond_to?(:scoped_by_tenant?) && MultiTenant.current_tenant_id
|
6
|
-
unscoped_orig.where(arel_table[
|
6
|
+
unscoped_orig.where(arel_table[self.partition_key].eq(MultiTenant.current_tenant_id))
|
7
7
|
else
|
8
8
|
unscoped_orig
|
9
9
|
end
|
@@ -27,7 +27,7 @@ module ActiveRecord
|
|
27
27
|
ret = orig_create_table(table_name, options.except(:partition_key), &block)
|
28
28
|
if options[:partition_key] && options[:partition_key].to_s != 'id'
|
29
29
|
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{table_name}_pkey"
|
30
|
-
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(id, #{options[:partition_key]})"
|
30
|
+
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(id, \"#{options[:partition_key]}\")"
|
31
31
|
end
|
32
32
|
ret
|
33
33
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module MultiTenant
|
2
|
+
module ModelExtensionsClassMethods
|
3
|
+
def multi_tenant(tenant, options = {})
|
4
|
+
# Workaround for https://github.com/citusdata/citus/issues/687
|
5
|
+
if to_s.underscore.to_sym == tenant
|
6
|
+
before_create -> { self.id ||= self.class.connection.select_value("SELECT nextval('" + [self.class.table_name, self.class.primary_key, 'seq'].join('_') + "'::regclass)") }
|
7
|
+
end
|
8
|
+
|
9
|
+
# Typically we don't need to run on the tenant model itself
|
10
|
+
if to_s.underscore.to_sym != tenant
|
11
|
+
# Provide fallback primary key setting to ease integration with the typical Rails app
|
12
|
+
self.primary_key = 'id' if primary_key.nil?
|
13
|
+
|
14
|
+
MultiTenant.set_tenant_klass(tenant)
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def scoped_by_tenant?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def partition_key
|
22
|
+
@partition_key
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@partition_key = options[:partition_key] || MultiTenant.partition_key
|
27
|
+
partition_key = @partition_key
|
28
|
+
|
29
|
+
# Create the association
|
30
|
+
belongs_to tenant, options.slice(:class_name, :inverse_of).merge(foreign_key: partition_key)
|
31
|
+
|
32
|
+
# Ensure all queries include the partition key
|
33
|
+
default_scope lambda {
|
34
|
+
if MultiTenant.current_tenant_id
|
35
|
+
where(partition_key.to_sym => MultiTenant.current_tenant_id)
|
36
|
+
else
|
37
|
+
Rails::VERSION::MAJOR < 4 ? scoped : all
|
38
|
+
end
|
39
|
+
}
|
40
|
+
|
41
|
+
# New instances should have the tenant set
|
42
|
+
before_validation Proc.new { |record|
|
43
|
+
if MultiTenant.current_tenant_id && record.public_send(partition_key.to_sym).nil?
|
44
|
+
record.public_send("#{partition_key}=".to_sym, MultiTenant.current_tenant_id)
|
45
|
+
end
|
46
|
+
}, on: :create
|
47
|
+
|
48
|
+
# Validate that associations belong to the tenant, currently only for belongs_to
|
49
|
+
polymorphic_foreign_keys = reflect_on_all_associations(:belongs_to).select do |a|
|
50
|
+
a.options[:polymorphic]
|
51
|
+
end.map { |a| a.foreign_key }
|
52
|
+
|
53
|
+
reflect_on_all_associations(:belongs_to).each do |a|
|
54
|
+
unless a == reflect_on_association(tenant) || polymorphic_foreign_keys.include?(a.foreign_key)
|
55
|
+
association_class = a.options[:class_name].nil? ? a.name.to_s.classify.constantize : a.options[:class_name].constantize
|
56
|
+
validates_each a.foreign_key.to_sym do |record, attr, value|
|
57
|
+
primary_key = if association_class.respond_to?(:primary_key)
|
58
|
+
association_class.primary_key
|
59
|
+
else
|
60
|
+
a.primary_key
|
61
|
+
end.to_sym
|
62
|
+
record.errors.add attr, 'association is invalid [MultiTenant]' unless value.nil? || association_class.where(primary_key => value).any?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
to_include = Module.new do
|
68
|
+
define_method "#{partition_key}=" do |integer|
|
69
|
+
write_attribute("#{partition_key}", integer)
|
70
|
+
raise MultiTenant::TenantIsImmutable if send("#{partition_key}_changed?") && persisted? && !send("#{partition_key}_was").nil?
|
71
|
+
integer
|
72
|
+
end
|
73
|
+
|
74
|
+
define_method "#{MultiTenant.tenant_klass.to_s}=" do |model|
|
75
|
+
super(model)
|
76
|
+
raise MultiTenant::TenantIsImmutable if send("#{partition_key}_changed?") && persisted? && !send("#{partition_key}_was").nil?
|
77
|
+
model
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method "#{MultiTenant.tenant_klass.to_s}" do
|
81
|
+
if !MultiTenant.current_tenant.nil? && !MultiTenant.current_tenant.is_a?(MultiTenant::TenantIdWrapper) && public_send(partition_key) == MultiTenant.current_tenant.id
|
82
|
+
return MultiTenant.current_tenant
|
83
|
+
else
|
84
|
+
super()
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
include to_include
|
89
|
+
|
90
|
+
around_save -> (record, block) {
|
91
|
+
if persisted? && MultiTenant.current_tenant_id.nil?
|
92
|
+
MultiTenant.with_id(record.public_send(partition_key)) { block.call }
|
93
|
+
else
|
94
|
+
block.call
|
95
|
+
end
|
96
|
+
}
|
97
|
+
|
98
|
+
around_update -> (record, block) {
|
99
|
+
if MultiTenant.current_tenant_id.nil?
|
100
|
+
MultiTenant.with_id(record.public_send(partition_key)) { block.call }
|
101
|
+
else
|
102
|
+
block.call
|
103
|
+
end
|
104
|
+
}
|
105
|
+
|
106
|
+
around_destroy -> (record, block) {
|
107
|
+
if MultiTenant.current_tenant_id.nil?
|
108
|
+
MultiTenant.with_id(record.public_send(partition_key)) { block.call }
|
109
|
+
else
|
110
|
+
block.call
|
111
|
+
end
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
if defined?(ActiveRecord::Base)
|
119
|
+
ActiveRecord::Base.extend(MultiTenant::ModelExtensionsClassMethods)
|
120
|
+
end
|
@@ -1,30 +1,51 @@
|
|
1
|
-
|
2
|
-
# calling acts_as_tenant methods directly as a user of this library
|
3
|
-
require 'acts_as_tenant'
|
1
|
+
require 'request_store'
|
4
2
|
|
5
3
|
module MultiTenant
|
6
|
-
|
7
|
-
|
4
|
+
@@tenant_klass = nil
|
5
|
+
|
6
|
+
def self.set_tenant_klass(klass)
|
7
|
+
@@tenant_klass = klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.tenant_klass
|
11
|
+
@@tenant_klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.partition_key
|
15
|
+
"#{@@tenant_klass.to_s}_id"
|
8
16
|
end
|
9
17
|
|
10
18
|
def self.current_tenant=(tenant)
|
11
|
-
|
19
|
+
RequestStore.store[:current_tenant] = tenant
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.current_tenant
|
23
|
+
RequestStore.store[:current_tenant]
|
12
24
|
end
|
13
25
|
|
14
26
|
def self.current_tenant_id
|
15
|
-
|
27
|
+
current_tenant.try(:id)
|
16
28
|
end
|
17
29
|
|
18
30
|
def self.with(tenant, &block)
|
19
|
-
|
20
|
-
|
31
|
+
old_tenant = self.current_tenant
|
32
|
+
self.current_tenant = tenant
|
33
|
+
value = block.call
|
34
|
+
return value
|
21
35
|
|
22
|
-
|
23
|
-
|
36
|
+
ensure
|
37
|
+
self.current_tenant = old_tenant
|
24
38
|
end
|
25
39
|
|
26
40
|
def self.with_id(tenant_id, &block)
|
27
|
-
MultiTenant.
|
41
|
+
if MultiTenant.current_tenant_id == tenant_id
|
42
|
+
block.call
|
43
|
+
else
|
44
|
+
MultiTenant.with(TenantIdWrapper.new(id: tenant_id), &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class TenantIsImmutable < StandardError
|
28
49
|
end
|
29
50
|
|
30
51
|
class TenantIdWrapper
|
@@ -37,36 +58,4 @@ module MultiTenant
|
|
37
58
|
def new_record?; true; end
|
38
59
|
def touch; nil; end
|
39
60
|
end
|
40
|
-
|
41
|
-
module ModelExtensions
|
42
|
-
def self.included(base)
|
43
|
-
base.extend(ClassMethods)
|
44
|
-
end
|
45
|
-
|
46
|
-
module ClassMethods
|
47
|
-
def multi_tenant(tenant, options = {})
|
48
|
-
# Provide fallback primary key setting to ease integration with the typical Rails app
|
49
|
-
self.primary_key = 'id' if primary_key.nil?
|
50
|
-
|
51
|
-
# Typically we don't need to run on the tenant model itself
|
52
|
-
if to_s.underscore.to_sym != tenant
|
53
|
-
belongs_to(tenant)
|
54
|
-
acts_as_tenant(tenant, options)
|
55
|
-
|
56
|
-
around_save -> (record, block) { persisted? ? MultiTenant.with_id(record.public_send(tenant.to_s + '_id')) { block.call } : block.call }
|
57
|
-
around_update -> (record, block) { MultiTenant.with_id(record.public_send(tenant.to_s + '_id')) { block.call } }
|
58
|
-
around_destroy -> (record, block) { MultiTenant.with_id(record.public_send(tenant.to_s + '_id')) { block.call } }
|
59
|
-
end
|
60
|
-
|
61
|
-
# Workaround for https://github.com/citusdata/citus/issues/687
|
62
|
-
if to_s.underscore.to_sym == tenant
|
63
|
-
before_create -> { self.id ||= self.class.connection.select_value("SELECT nextval('" + [self.class.table_name, self.class.primary_key, 'seq'].join('_') + "'::regclass)") }
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
if defined?(ActiveRecord::Base)
|
71
|
-
ActiveRecord::Base.send(:include, MultiTenant::ModelExtensions)
|
72
61
|
end
|