rls_multi_tenant 0.2.3 → 0.2.5

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: 397cee677030faceb292bbfbb2eda3bb87f269d6b1b834966b7e6601472b8bcc
4
- data.tar.gz: 42dff9f53f1d0ce4e1a59fd44e081bf33b2459083ecc63d6a19560a9c80fd4c9
3
+ metadata.gz: 7a8043bdc925d9f0e5e05d743f457e9baad7d861ccfa0f649bbc2b07f48c8958
4
+ data.tar.gz: 2476c3fbd98f58f8eb50be5cfbaeb95c6219a0aba2b77b250617a8d83970e16d
5
5
  SHA512:
6
- metadata.gz: f99ba4e9128a74857c708e8393d3c8302c900c79c2809c0ad0a8dd1723d7daf1bf5f0ac064376709eb0b73983e14ec4dd3228db053c4f3f063d62c5d7adb4e1e
7
- data.tar.gz: 65d310a74e59647771b1d3e37508d2e8b23050ceb501a64b6663c9c1532f5d43bb91e84a4c73c673f91e8a4a06d380db8c0b010ee411cf4b4dea3a746be5b084
6
+ metadata.gz: 2679ab3b6517e126ac6ba342ed6c1144af54e52bde076385ac73e5fa0d56db98dee75c4a71ad81136c0f11faf3bd1532bd5e9545c741badc34016fc0fb360244
7
+ data.tar.gz: ce18b2512ba1bbd63fd78388fbf752f66ea9eb4aa44aef8f16ec5ec2982c2f4996a24511f4e613a0b41916219ab557a4b0eb3a4ca70afa7b6e1cef07b6d8f2bf
data/.rubocop.yml CHANGED
@@ -3,12 +3,14 @@ plugins:
3
3
  - rubocop-rspec
4
4
 
5
5
  AllCops:
6
+ SuggestExtensions: false
6
7
  TargetRubyVersion: 3.0
7
8
  NewCops: enable
8
9
  Exclude:
9
10
  - 'vendor/**/*'
10
11
  - 'spec/tmp/**/*'
11
12
  - 'tmp/**/*'
13
+ - 'lib/rls_multi_tenant/generators/**/templates/**/*'
12
14
 
13
15
  Style/Documentation:
14
16
  Enabled: false
@@ -23,13 +25,17 @@ Style/ClassAndModuleChildren:
23
25
  Enabled: false
24
26
 
25
27
  Layout/LineLength:
26
- Max: 120
28
+ Max: 130
27
29
 
28
30
  Metrics/BlockLength:
31
+ Max: 50
29
32
  Exclude:
30
33
  - 'spec/**/*'
31
34
  - 'lib/rls_multi_tenant/generators/**/*'
32
35
 
36
+ Metrics/MethodLength:
37
+ Max: 25
38
+
33
39
  RSpec/ExampleLength:
34
40
  Max: 20
35
41
 
@@ -44,3 +50,6 @@ RSpec/DescribeClass:
44
50
 
45
51
  RSpec/DescribeMethod:
46
52
  Enabled: false
53
+
54
+ Gemspec/DevelopmentDependencies:
55
+ Enabled: false
@@ -6,7 +6,8 @@ module RlsMultiTenant
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- belongs_to :tenant, class_name: RlsMultiTenant.tenant_class_name, foreign_key: RlsMultiTenant.tenant_id_column
9
+ belongs_to :tenant, class_name: RlsMultiTenant.tenant_class_name.to_s,
10
+ foreign_key: RlsMultiTenant.tenant_id_column
10
11
 
11
12
  validates RlsMultiTenant.tenant_id_column, presence: true
12
13
 
@@ -26,22 +27,6 @@ module RlsMultiTenant
26
27
  end
27
28
  end
28
29
  end
29
-
30
- class_methods do
31
- private
32
-
33
- def extract_tenant_id(tenant_or_id)
34
- case tenant_or_id
35
- when RlsMultiTenant.tenant_class
36
- tenant_or_id.id
37
- when String, Integer
38
- tenant_or_id
39
- else
40
- raise ArgumentError,
41
- "Expected #{RlsMultiTenant.tenant_class_name} object or tenant_id, got #{tenant_or_id.class}"
42
- end
43
- end
44
- end
45
30
  end
46
31
  end
47
32
  end
@@ -53,7 +53,7 @@ module RlsMultiTenant
53
53
 
54
54
  def extract_tenant_id(tenant_or_id)
55
55
  case tenant_or_id
56
- when RlsMultiTenant.tenant_class
56
+ when ->(obj) { obj.is_a?(RlsMultiTenant.tenant_class) }
57
57
  tenant_or_id.id
58
58
  when String, Integer
59
59
  tenant_or_id
@@ -12,35 +12,56 @@ module RlsMultiTenant
12
12
  tenant = resolve_tenant_from_subdomain(request)
13
13
 
14
14
  if tenant
15
- # Switch tenant context for the duration of the request
16
- if defined?(Rails)
17
- Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Tenant: #{tenant.name} (#{tenant.id})"
18
- end
19
- RlsMultiTenant.tenant_class.switch(tenant) do
20
- @app.call(env)
21
- end
15
+ handle_tenant_request(env, request, tenant)
22
16
  else
23
- # No tenant found - check if we need tenant context
24
- subdomain = extract_subdomain(request.host)
25
- if subdomain.present? && subdomain != 'www'
26
- # Subdomain exists but no tenant found - this is an error
27
- if defined?(Rails)
28
- Rails.logger.warn "[RLS Multi-Tenant] #{request.method} #{request.path} -> No tenant found for subdomain '#{subdomain}'"
29
- end
30
- raise RlsMultiTenant::Error,
31
- "No tenant found for subdomain '#{subdomain}'. Please ensure the tenant exists with the correct subdomain."
32
- end
33
- # If no subdomain, allow access to public models (models without TenantContext)
34
- # Models that include TenantContext will automatically be constrained by RLS
35
- if defined?(Rails)
36
- Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Public access (no subdomain)"
37
- end
38
- @app.call(env)
17
+ handle_no_tenant_request(env, request)
39
18
  end
40
19
  end
41
20
 
42
21
  private
43
22
 
23
+ def handle_tenant_request(env, request, tenant)
24
+ log_tenant_access(request, tenant)
25
+ RlsMultiTenant.tenant_class.switch(tenant) do
26
+ @app.call(env)
27
+ end
28
+ end
29
+
30
+ def handle_no_tenant_request(env, request)
31
+ subdomain = extract_subdomain(request.host)
32
+
33
+ if subdomain.present? && subdomain != 'www'
34
+ handle_missing_tenant_error(request, subdomain)
35
+ else
36
+ handle_public_access(request)
37
+ @app.call(env)
38
+ end
39
+ end
40
+
41
+ def log_tenant_access(request, tenant)
42
+ return unless defined?(Rails)
43
+
44
+ Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Tenant: #{tenant.name} (#{tenant.id})"
45
+ end
46
+
47
+ def handle_missing_tenant_error(request, subdomain)
48
+ log_missing_tenant_warning(request, subdomain)
49
+ raise RlsMultiTenant::Error,
50
+ "No tenant found for subdomain '#{subdomain}'. Please ensure the tenant exists with the correct subdomain."
51
+ end
52
+
53
+ def log_missing_tenant_warning(request, subdomain)
54
+ return unless defined?(Rails)
55
+
56
+ Rails.logger.warn "[RLS Multi-Tenant] #{request.method} #{request.path} -> No tenant found for subdomain '#{subdomain}'"
57
+ end
58
+
59
+ def handle_public_access(request)
60
+ return unless defined?(Rails)
61
+
62
+ Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Public access (no subdomain)"
63
+ end
64
+
44
65
  def resolve_tenant_from_subdomain(request)
45
66
  subdomain = extract_subdomain(request.host)
46
67
  return nil if subdomain.blank? || subdomain == 'www'
@@ -71,13 +92,10 @@ module RlsMultiTenant
71
92
  # Split by dots and get the first part (subdomain)
72
93
  parts = host.split('.')
73
94
 
74
- # Handle localhost development (e.g., foo.localhost:3000)
75
- if parts.length == 2 && parts.last == 'localhost'
76
- parts.first
77
- # Handle standard domains (e.g., foo.example.com)
78
- elsif parts.length >= 3
79
- parts.first
80
- end
95
+ # Handle localhost development (e.g., foo.localhost:3000) or standard domains (e.g., foo.example.com)
96
+ return unless (parts.length == 2 && parts.last == 'localhost') || parts.length >= 3
97
+
98
+ parts.first
81
99
  end
82
100
  end
83
101
  end
@@ -31,9 +31,7 @@ module RlsMultiTenant
31
31
  end
32
32
 
33
33
  initializer 'rls_multi_tenant.middleware', after: :load_config_initializers do |app|
34
- if RlsMultiTenant.enable_subdomain_middleware
35
- app.config.middleware.use RlsMultiTenant::Middleware::SubdomainTenantSelector
36
- end
34
+ app.config.middleware.use RlsMultiTenant::Middleware::SubdomainTenantSelector if RlsMultiTenant.enable_subdomain_middleware
37
35
  end
38
36
  end
39
37
  end
@@ -14,13 +14,17 @@ module RlsMultiTenant
14
14
 
15
15
  # Configuration options
16
16
  class << self
17
- attr_accessor :tenant_class_name, :tenant_id_column, :enable_security_validation, :enable_subdomain_middleware,
18
- :subdomain_field
17
+ attr_writer :tenant_class_name, :tenant_id_column, :enable_security_validation, :enable_subdomain_middleware,
18
+ :subdomain_field
19
19
 
20
20
  def configure
21
21
  yield self
22
22
  end
23
23
 
24
+ def tenant_class_name
25
+ @tenant_class_name ||= 'Tenant'
26
+ end
27
+
24
28
  def tenant_class
25
29
  @tenant_class ||= tenant_class_name.constantize
26
30
  end
@@ -18,7 +18,8 @@ module RlsMultiTenant
18
18
 
19
19
  if bypassrls_check && bypassrls_check['rolbypassrls']
20
20
  raise SecurityError, "Database user '#{username}' has BYPASSRLS privilege. " \
21
- 'In order to use RLS Multi-tenant, you must use a non-privileged user without BYPASSRLS privilege.'
21
+ 'In order to use RLS Multi-tenant, you must use a non-privileged user ' \
22
+ 'without BYPASSRLS privilege.'
22
23
  end
23
24
 
24
25
  # Log the security check result
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RlsMultiTenant
4
- VERSION = '0.2.3'
4
+ VERSION = '0.2.5'
5
5
  end
@@ -16,13 +16,17 @@ module RlsMultiTenant
16
16
 
17
17
  # Configuration options
18
18
  class << self
19
- attr_accessor :tenant_class_name, :tenant_id_column, :enable_security_validation, :enable_subdomain_middleware,
20
- :subdomain_field
19
+ attr_writer :tenant_class_name, :tenant_id_column, :enable_security_validation, :enable_subdomain_middleware,
20
+ :subdomain_field
21
21
 
22
22
  def configure
23
23
  yield self
24
24
  end
25
25
 
26
+ def tenant_class_name
27
+ @tenant_class_name ||= 'Tenant'
28
+ end
29
+
26
30
  def tenant_class
27
31
  @tenant_class ||= tenant_class_name.constantize
28
32
  end
@@ -9,7 +9,9 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ['info@codingways.com']
10
10
 
11
11
  spec.summary = 'Rails gem for PostgreSQL Row Level Security (RLS) multi-tenant applications'
12
- spec.description = 'A comprehensive gem that provides RLS-based multi-tenancy for Rails applications using PostgreSQL, including automatic tenant context switching, security validations, and migration helpers.'
12
+ spec.description = 'A comprehensive gem that provides RLS-based multi-tenancy for Rails applications ' \
13
+ 'using PostgreSQL, including automatic tenant context switching, security ' \
14
+ 'validations, and migration helpers.'
13
15
  spec.homepage = 'https://github.com/codingways/rls_multi_tenant'
14
16
  spec.license = 'MIT'
15
17
  spec.required_ruby_version = '>= 3.0.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rls_multi_tenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Coding Ways