activerecord-tenanted 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62c3b9d7f37db44de60c7559e4b10e1407171ab29aa874e2687853e8acc38bb1
4
- data.tar.gz: 27b2ee871ff4ce67b60480e83694cf6a2aeac504b3ab39f96ea0eb243b5f3a47
3
+ metadata.gz: e1981c6ea91e6ef43e674e0f6d3bba9eebe8b1852f0745df774cf571c03d3c54
4
+ data.tar.gz: 4f8d4c87cdb079ec884aa3391384cae1134f025204aacbe2c4ad22a6ae204f7b
5
5
  SHA512:
6
- metadata.gz: 7eff54730cbc865dd8ecb1169e146194b0edceaed0527059ed110537aedd57901a5a5af5b85c522bfebcf50714c468984f91ac4f5c8e40077b2e737497eac550
7
- data.tar.gz: fafa6f206173a7057e090407f5cf6698bd7f1d34885509793568f1e76baedbe61b7eeea980493b5af0df30c3f5bd20400c799eebecf62785f458e925afbee57f
6
+ metadata.gz: c3258b8a167dd07e0f8f63ce0307429cd626761b4e26bb6ef3279063c119b595660613498667eafbcf5ea3eedc2f0d5603d395f14e8ec05ab1fdf9300bf2c5dc
7
+ data.tar.gz: 11e72266e807ae48685454eadbed040b586d1ddc6bc284954ae36267afc2c2ef0ae3d19dbc67408bb7d3705fb352319d2a4e8268cdf520e02910725c742f41c4
@@ -24,8 +24,6 @@ module ActiveRecord
24
24
  end
25
25
  end
26
26
 
27
- # TODO: This monkey patch shouldn't be necessary after 8.1 lands and the need for a
28
- # connection is removed. For details see https://github.com/rails/rails/pull/54348
29
27
  module Attributes
30
28
  extend ActiveSupport::Concern
31
29
 
@@ -44,6 +42,18 @@ module ActiveRecord
44
42
  end
45
43
  end
46
44
  end
45
+
46
+ class << self
47
+ # This monkey patch isn't necessary after 8.1 removed the need for a connection.
48
+ # For details see https://github.com/rails/rails/pull/54348
49
+ def needs_patch?
50
+ Gem::Requirement.new("~> 8.1.0").satisfied_by?(Gem::Version.new(Rails::VERSION::STRING))
51
+ end
52
+
53
+ def apply_patch
54
+ ActiveRecord::Base.prepend(self) if needs_patch?
55
+ end
56
+ end
47
57
  end
48
58
  end
49
59
  end
@@ -95,7 +95,7 @@ module ActiveRecord
95
95
 
96
96
  initializer "active_record_tenanted.monkey_patches" do
97
97
  ActiveSupport.on_load(:active_record) do
98
- prepend ActiveRecord::Tenanted::Patches::Attributes
98
+ ActiveRecord::Tenanted::Patches::Attributes.apply_patch
99
99
  ActiveRecord::Tasks::DatabaseTasks.prepend ActiveRecord::Tenanted::Patches::DatabaseTasks
100
100
  end
101
101
  end
@@ -17,16 +17,31 @@ module ActiveRecord
17
17
  end
18
18
 
19
19
  def path_for(key)
20
- if ActiveRecord::Tenanted.connection_class
21
- # TODO: this is brittle if the key isn't tenanted ... errors in folder_for:
22
- #
23
- # NoMethodError undefined method '[]' for nil (NoMethodError) [ key[0..1], key[2..3] ].join("/")
24
- #
25
- tenant, key = key.split("/", 2)
26
- File.join(root, tenant, folder_for(key), key)
27
- else
28
- super
20
+ return super unless ActiveRecord::Tenanted.connection_class && key.include?("/")
21
+
22
+ if key.split("/").intersect?(%w[. ..])
23
+ raise ActiveStorage::InvalidKeyError, "key has path traversal segments"
24
+ end
25
+
26
+ tenant, key = key.split("/", 2)
27
+
28
+ if tenant.blank? || key.blank?
29
+ raise ActiveStorage::InvalidKeyError, "key has a blank segment"
29
30
  end
31
+
32
+ begin
33
+ path = File.expand_path(File.join(root, tenant, folder_for(key), key))
34
+ rescue ArgumentError
35
+ raise ActiveStorage::InvalidKeyError, "key is an invalid string"
36
+ end
37
+
38
+ unless path.start_with?(File.expand_path(root) + "/")
39
+ raise ActiveStorage::InvalidKeyError, "key is outside of disk service root"
40
+ end
41
+
42
+ path
43
+ rescue Encoding::CompatibilityError
44
+ raise ActiveStorage::InvalidKeyError, "key has incompatible encoding"
30
45
  end
31
46
  end
32
47
 
@@ -95,9 +95,18 @@ module ActiveRecord
95
95
  end
96
96
 
97
97
  def current_tenant=(tenant_name)
98
- tenant_name = tenant_name.to_s unless tenant_name == UNTENANTED_SENTINEL
98
+ case tenant_name
99
+ when nil
100
+ tenant_name = UNTENANTED_SENTINEL
101
+ when UNTENANTED_SENTINEL
102
+ # no-op
103
+ else
104
+ tenant_name = tenant_name.to_s
105
+ end
99
106
 
100
- connection_class_for_self.connecting_to(shard: tenant_name, role: ActiveRecord.writing_role)
107
+ run_callbacks :set_current_tenant do
108
+ connection_class_for_self.connecting_to(shard: tenant_name, role: ActiveRecord.writing_role)
109
+ end
101
110
  end
102
111
 
103
112
  def tenant_exist?(tenant_name)
@@ -108,11 +117,13 @@ module ActiveRecord
108
117
  tenant_name = tenant_name.to_s unless tenant_name == UNTENANTED_SENTINEL
109
118
 
110
119
  if tenant_name == current_tenant
111
- yield
120
+ run_callbacks :with_tenant, &block
112
121
  else
113
122
  connection_class_for_self.connected_to(shard: tenant_name, role: ActiveRecord.writing_role) do
114
- prohibit_shard_swapping(prohibit_shard_swapping) do
115
- log_tenant_tag(tenant_name, &block)
123
+ run_callbacks :with_tenant do
124
+ prohibit_shard_swapping(prohibit_shard_swapping) do
125
+ log_tenant_tag(tenant_name, &block)
126
+ end
116
127
  end
117
128
  end
118
129
  end
@@ -255,9 +266,13 @@ module ActiveRecord
255
266
  self.default_shard = ActiveRecord::Tenanted::Tenant::UNTENANTED_SENTINEL
256
267
 
257
268
  prepend TenantCommon
269
+ extend ActiveSupport::Callbacks
258
270
 
259
271
  cattr_accessor :tenanted_config_name
260
272
  cattr_accessor(:tenanted_connection_pools) { LRU.new }
273
+
274
+ define_callbacks :with_tenant
275
+ define_callbacks :set_current_tenant
261
276
  end
262
277
 
263
278
  def tenanted?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Tenanted
5
- VERSION = "0.6.0"
5
+ VERSION = "0.7.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-tenanted
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dalessio
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 8.1.beta
18
+ version: 8.1.2.1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 8.1.beta
25
+ version: 8.1.2.1
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: railties
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 8.1.beta
32
+ version: 8.1.2.1
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 8.1.beta
39
+ version: 8.1.2.1
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: zeitwerk
42
42
  requirement: !ruby/object:Gem::Requirement