pg_multitenant_schemas 0.1.3
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 +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +372 -0
- data/.rubocop_simple.yml +0 -0
- data/CHANGELOG.md +50 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +149 -0
- data/Rakefile +12 -0
- data/lib/pg_multitenant_schemas/configuration.rb +37 -0
- data/lib/pg_multitenant_schemas/context.rb +106 -0
- data/lib/pg_multitenant_schemas/errors.rb +11 -0
- data/lib/pg_multitenant_schemas/rails/controller_concern.rb +73 -0
- data/lib/pg_multitenant_schemas/rails/model_concern.rb +88 -0
- data/lib/pg_multitenant_schemas/rails/railtie.rb +27 -0
- data/lib/pg_multitenant_schemas/schema_switcher.rb +141 -0
- data/lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake +155 -0
- data/lib/pg_multitenant_schemas/tenant_resolver.rb +92 -0
- data/lib/pg_multitenant_schemas/version.rb +5 -0
- data/lib/pg_multitenant_schemas.rb +33 -0
- data/pg_multitenant_schemas.gemspec +40 -0
- data/rails_integration/app/controllers/application_controller.rb +0 -0
- data/rails_integration/app/models/tenant.rb +0 -0
- data/sig/pg_multitenant_schemas.rbs +4 -0
- metadata +126 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :pg_multitenant_schemas do
|
|
4
|
+
desc "List all tenant schemas"
|
|
5
|
+
task :list_schemas => :environment do
|
|
6
|
+
puts "Available tenant schemas:"
|
|
7
|
+
|
|
8
|
+
connection = ActiveRecord::Base.connection
|
|
9
|
+
schemas = connection.execute(
|
|
10
|
+
"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema', 'pg_catalog', 'pg_toast_temp_1', 'pg_temp_1', 'public') AND schema_name NOT LIKE 'pg_toast%'"
|
|
11
|
+
).map { |row| row['schema_name'] }
|
|
12
|
+
|
|
13
|
+
if schemas.any?
|
|
14
|
+
schemas.each { |schema| puts " - #{schema}" }
|
|
15
|
+
else
|
|
16
|
+
puts " No tenant schemas found"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
desc "Create schema for a tenant"
|
|
21
|
+
task :create_schema, [:schema_name] => :environment do |task, args|
|
|
22
|
+
schema_name = args[:schema_name]
|
|
23
|
+
|
|
24
|
+
if schema_name.blank?
|
|
25
|
+
puts "Usage: rails pg_multitenant_schemas:create_schema[schema_name]"
|
|
26
|
+
exit 1
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
connection = ActiveRecord::Base.connection
|
|
31
|
+
PgMultitenantSchemas::SchemaSwitcher.create_schema(connection, schema_name)
|
|
32
|
+
puts "Created schema: #{schema_name}"
|
|
33
|
+
rescue => e
|
|
34
|
+
puts "Error creating schema #{schema_name}: #{e.message}"
|
|
35
|
+
exit 1
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
desc "Drop schema for a tenant"
|
|
40
|
+
task :drop_schema, [:schema_name] => :environment do |task, args|
|
|
41
|
+
schema_name = args[:schema_name]
|
|
42
|
+
|
|
43
|
+
if schema_name.blank?
|
|
44
|
+
puts "Usage: rails pg_multitenant_schemas:drop_schema[schema_name]"
|
|
45
|
+
exit 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if schema_name == 'public'
|
|
49
|
+
puts "Cannot drop public schema"
|
|
50
|
+
exit 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
begin
|
|
54
|
+
connection = ActiveRecord::Base.connection
|
|
55
|
+
PgMultitenantSchemas::SchemaSwitcher.drop_schema(connection, schema_name)
|
|
56
|
+
puts "Dropped schema: #{schema_name}"
|
|
57
|
+
rescue => e
|
|
58
|
+
puts "Error dropping schema #{schema_name}: #{e.message}"
|
|
59
|
+
exit 1
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc "Run migrations for all tenant schemas"
|
|
64
|
+
task :migrate_all => :environment do
|
|
65
|
+
puts "Running migrations for all tenant schemas..."
|
|
66
|
+
|
|
67
|
+
connection = ActiveRecord::Base.connection
|
|
68
|
+
schemas = connection.execute(
|
|
69
|
+
"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema', 'pg_catalog', 'pg_toast_temp_1', 'pg_temp_1', 'public') AND schema_name NOT LIKE 'pg_toast%'"
|
|
70
|
+
).map { |row| row['schema_name'] }
|
|
71
|
+
|
|
72
|
+
original_schema = PgMultitenantSchemas.current_schema rescue 'public'
|
|
73
|
+
|
|
74
|
+
schemas.each do |schema|
|
|
75
|
+
puts "Migrating schema: #{schema}"
|
|
76
|
+
begin
|
|
77
|
+
PgMultitenantSchemas.with_tenant(schema) do
|
|
78
|
+
# Rails 8 compatible migration execution
|
|
79
|
+
if Rails.version >= "8.0"
|
|
80
|
+
# Use Rails 8 migration API
|
|
81
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
|
82
|
+
else
|
|
83
|
+
# Fallback for older Rails versions
|
|
84
|
+
ActiveRecord::Migrator.migrate(Rails.application.paths["db/migrate"])
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
puts " ✓ Completed migration for #{schema}"
|
|
88
|
+
rescue => e
|
|
89
|
+
puts " ✗ Error migrating #{schema}: #{e.message}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Restore original schema
|
|
94
|
+
PgMultitenantSchemas.current_schema = original_schema if defined?(PgMultitenantSchemas)
|
|
95
|
+
|
|
96
|
+
puts "Completed migrations for #{schemas.count} schemas"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
desc "Setup multitenancy - create tenant schemas for existing tenants"
|
|
100
|
+
task :setup => :environment do
|
|
101
|
+
puts "Setting up multitenancy schemas..."
|
|
102
|
+
|
|
103
|
+
if defined?(Tenant)
|
|
104
|
+
tenants = Tenant.all
|
|
105
|
+
|
|
106
|
+
tenants.each do |tenant|
|
|
107
|
+
begin
|
|
108
|
+
puts "Creating schema for tenant: #{tenant.subdomain}"
|
|
109
|
+
PgMultitenantSchemas::SchemaSwitcher.create_schema(
|
|
110
|
+
ActiveRecord::Base.connection,
|
|
111
|
+
tenant.subdomain
|
|
112
|
+
)
|
|
113
|
+
puts " ✓ Schema created for #{tenant.subdomain}"
|
|
114
|
+
rescue => e
|
|
115
|
+
if e.message.include?("already exists")
|
|
116
|
+
puts " - Schema #{tenant.subdomain} already exists"
|
|
117
|
+
else
|
|
118
|
+
puts " ✗ Could not create schema for #{tenant.subdomain}: #{e.message}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
puts "Setup completed for #{tenants.count} tenants"
|
|
124
|
+
else
|
|
125
|
+
puts "Tenant model not found. Make sure your Tenant model is defined."
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
desc "Run migrations for a specific tenant schema"
|
|
130
|
+
task :migrate_tenant, [:schema_name] => :environment do |task, args|
|
|
131
|
+
schema_name = args[:schema_name]
|
|
132
|
+
|
|
133
|
+
if schema_name.blank?
|
|
134
|
+
puts "Usage: rails pg_multitenant_schemas:migrate_tenant[schema_name]"
|
|
135
|
+
exit 1
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
puts "Running migrations for tenant: #{schema_name}"
|
|
139
|
+
|
|
140
|
+
begin
|
|
141
|
+
PgMultitenantSchemas.with_tenant(schema_name) do
|
|
142
|
+
# Rails 8 compatible migration execution
|
|
143
|
+
if Rails.version >= "8.0"
|
|
144
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
|
145
|
+
else
|
|
146
|
+
ActiveRecord::Migrator.migrate(Rails.application.paths["db/migrate"])
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
puts "✓ Completed migration for #{schema_name}"
|
|
150
|
+
rescue => e
|
|
151
|
+
puts "✗ Error migrating #{schema_name}: #{e.message}"
|
|
152
|
+
exit 1
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgMultitenantSchemas
|
|
4
|
+
# Tenant resolution from HTTP requests
|
|
5
|
+
class TenantResolver
|
|
6
|
+
class << self
|
|
7
|
+
# Extract subdomain from host
|
|
8
|
+
def extract_subdomain(host)
|
|
9
|
+
return nil if invalid_host?(host)
|
|
10
|
+
|
|
11
|
+
host = clean_host(host)
|
|
12
|
+
parts = host.split(".")
|
|
13
|
+
return nil if parts.length < 2
|
|
14
|
+
|
|
15
|
+
subdomain = parts.first.downcase
|
|
16
|
+
return nil if excluded_subdomain?(subdomain, parts)
|
|
17
|
+
|
|
18
|
+
subdomain
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# Check if host is invalid for subdomain extraction
|
|
24
|
+
def invalid_host?(host)
|
|
25
|
+
host.blank? || host == "localhost" || host.match?(/\A\d+\.\d+\.\d+\.\d+/)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Clean host by removing port
|
|
29
|
+
def clean_host(host)
|
|
30
|
+
host.split(":").first
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Check if subdomain should be excluded
|
|
34
|
+
def excluded_subdomain?(subdomain, parts)
|
|
35
|
+
# Exclude common subdomains for standard domains (3 parts or fewer)
|
|
36
|
+
# Allow them for complex subdomains (4+ parts like api.company.example.com)
|
|
37
|
+
if parts.length <= 3
|
|
38
|
+
excluded_subdomains = PgMultitenantSchemas.configuration.excluded_subdomains
|
|
39
|
+
return true if excluded_subdomains.include?(subdomain)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# For exactly 2 parts, also check if second part is a common TLD
|
|
43
|
+
if parts.length == 2
|
|
44
|
+
common_tlds = PgMultitenantSchemas.configuration.common_tlds
|
|
45
|
+
return true if common_tlds.include?(parts.last.downcase)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
public
|
|
52
|
+
|
|
53
|
+
# Find tenant by subdomain (only active tenants)
|
|
54
|
+
def find_tenant_by_subdomain(subdomain)
|
|
55
|
+
return nil if subdomain.blank?
|
|
56
|
+
|
|
57
|
+
tenant_model = PgMultitenantSchemas.configuration.tenant_model
|
|
58
|
+
|
|
59
|
+
# Attempt to find active tenant
|
|
60
|
+
if tenant_model.respond_to?(:active)
|
|
61
|
+
tenant_model.active.find_by(subdomain: subdomain)
|
|
62
|
+
else
|
|
63
|
+
tenant_model.find_by(subdomain: subdomain, status: "active")
|
|
64
|
+
end
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
Rails.logger.error "PgMultitenantSchemas: Error finding tenant '#{subdomain}': #{e.message}"
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Resolve tenant from request
|
|
71
|
+
def resolve_tenant_from_request(request)
|
|
72
|
+
subdomain = extract_subdomain(request.host)
|
|
73
|
+
return nil if subdomain.blank?
|
|
74
|
+
|
|
75
|
+
find_tenant_by_subdomain(subdomain)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Resolve tenant with fallback options
|
|
79
|
+
def resolve_tenant_with_fallback(request)
|
|
80
|
+
tenant = resolve_tenant_from_request(request)
|
|
81
|
+
|
|
82
|
+
# If no tenant found and development fallback is enabled
|
|
83
|
+
if tenant.nil? && PgMultitenantSchemas.configuration.development_fallback && Rails.env.development?
|
|
84
|
+
Rails.logger.info "PgMultitenantSchemas: No tenant found, using development fallback"
|
|
85
|
+
return nil # This will cause switch to default schema
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
tenant
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/module/delegation"
|
|
4
|
+
require "active_support/core_ext/object/blank"
|
|
5
|
+
require_relative "pg_multitenant_schemas/version"
|
|
6
|
+
require_relative "pg_multitenant_schemas/errors"
|
|
7
|
+
require_relative "pg_multitenant_schemas/configuration"
|
|
8
|
+
require_relative "pg_multitenant_schemas/schema_switcher"
|
|
9
|
+
require_relative "pg_multitenant_schemas/context"
|
|
10
|
+
require_relative "pg_multitenant_schemas/tenant_resolver"
|
|
11
|
+
|
|
12
|
+
# Rails integration (only load if Rails is available)
|
|
13
|
+
if defined?(Rails)
|
|
14
|
+
require_relative "pg_multitenant_schemas/rails/controller_concern"
|
|
15
|
+
require_relative "pg_multitenant_schemas/rails/model_concern"
|
|
16
|
+
require_relative "pg_multitenant_schemas/rails/railtie"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# PgMultitenantSchemas provides PostgreSQL schema-based multitenancy functionality.
|
|
20
|
+
# It allows switching between different PostgreSQL schemas to achieve tenant isolation
|
|
21
|
+
# while sharing the same database connection. Includes Rails integration support.
|
|
22
|
+
module PgMultitenantSchemas
|
|
23
|
+
class << self
|
|
24
|
+
# Delegate common methods to Context for convenience
|
|
25
|
+
delegate :current_tenant, :current_tenant=, :current_schema, :current_schema=,
|
|
26
|
+
:reset!, :switch_to_schema, :switch_to_tenant, :with_tenant,
|
|
27
|
+
:create_tenant_schema, :drop_tenant_schema, to: :"PgMultitenantSchemas::Context"
|
|
28
|
+
|
|
29
|
+
# Delegate tenant resolution to TenantResolver
|
|
30
|
+
delegate :extract_subdomain, :find_tenant_by_subdomain, :resolve_tenant_from_request,
|
|
31
|
+
to: :"PgMultitenantSchemas::TenantResolver"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/pg_multitenant_schemas/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "pg_multitenant_schemas"
|
|
7
|
+
spec.version = PgMultitenantSchemas::VERSION
|
|
8
|
+
spec.authors = ["Ruben Paz"]
|
|
9
|
+
spec.email = ["rubenpazchuspe@outlook.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "PostgreSQL schema-based multitenancy for Rails applications"
|
|
12
|
+
spec.description = "A Ruby gem that provides PostgreSQL schema-based multitenancy with automatic tenant " \
|
|
13
|
+
"resolution, schema switching, Rails 8 compatibility, and comprehensive Rails integration. " \
|
|
14
|
+
"Perfect for SaaS applications requiring secure tenant isolation."
|
|
15
|
+
spec.homepage = "https://github.com/rubenpazch/pg_multitenant_schemas"
|
|
16
|
+
spec.license = "MIT"
|
|
17
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
18
|
+
|
|
19
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
20
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
21
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
22
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
23
|
+
|
|
24
|
+
# Specify which files should be added to the gem when it is released.
|
|
25
|
+
spec.files = Dir.chdir(__dir__) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
27
|
+
(File.expand_path(f) == __FILE__) ||
|
|
28
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile]) ||
|
|
29
|
+
f.end_with?(".gem")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
spec.bindir = "exe"
|
|
33
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
34
|
+
spec.require_paths = ["lib"]
|
|
35
|
+
|
|
36
|
+
# Runtime dependencies - Rails 8 compatible
|
|
37
|
+
spec.add_dependency "activerecord", ">= 7.0", "< 9.0"
|
|
38
|
+
spec.add_dependency "activesupport", ">= 7.0", "< 9.0"
|
|
39
|
+
spec.add_dependency "pg", "~> 1.0"
|
|
40
|
+
end
|
|
File without changes
|
|
File without changes
|
metadata
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pg_multitenant_schemas
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.3
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ruben Paz
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-09-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7.0'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '7.0'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9.0'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: activesupport
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '7.0'
|
|
40
|
+
- - "<"
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '9.0'
|
|
43
|
+
type: :runtime
|
|
44
|
+
prerelease: false
|
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '7.0'
|
|
50
|
+
- - "<"
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '9.0'
|
|
53
|
+
- !ruby/object:Gem::Dependency
|
|
54
|
+
name: pg
|
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - "~>"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '1.0'
|
|
60
|
+
type: :runtime
|
|
61
|
+
prerelease: false
|
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - "~>"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '1.0'
|
|
67
|
+
description: A Ruby gem that provides PostgreSQL schema-based multitenancy with automatic
|
|
68
|
+
tenant resolution, schema switching, Rails 8 compatibility, and comprehensive Rails
|
|
69
|
+
integration. Perfect for SaaS applications requiring secure tenant isolation.
|
|
70
|
+
email:
|
|
71
|
+
- rubenpazchuspe@outlook.com
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- ".rspec"
|
|
77
|
+
- ".rubocop.yml"
|
|
78
|
+
- ".rubocop_simple.yml"
|
|
79
|
+
- CHANGELOG.md
|
|
80
|
+
- CODE_OF_CONDUCT.md
|
|
81
|
+
- LICENSE.txt
|
|
82
|
+
- README.md
|
|
83
|
+
- Rakefile
|
|
84
|
+
- lib/pg_multitenant_schemas.rb
|
|
85
|
+
- lib/pg_multitenant_schemas/configuration.rb
|
|
86
|
+
- lib/pg_multitenant_schemas/context.rb
|
|
87
|
+
- lib/pg_multitenant_schemas/errors.rb
|
|
88
|
+
- lib/pg_multitenant_schemas/rails/controller_concern.rb
|
|
89
|
+
- lib/pg_multitenant_schemas/rails/model_concern.rb
|
|
90
|
+
- lib/pg_multitenant_schemas/rails/railtie.rb
|
|
91
|
+
- lib/pg_multitenant_schemas/schema_switcher.rb
|
|
92
|
+
- lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake
|
|
93
|
+
- lib/pg_multitenant_schemas/tenant_resolver.rb
|
|
94
|
+
- lib/pg_multitenant_schemas/version.rb
|
|
95
|
+
- pg_multitenant_schemas.gemspec
|
|
96
|
+
- rails_integration/app/controllers/application_controller.rb
|
|
97
|
+
- rails_integration/app/models/tenant.rb
|
|
98
|
+
- sig/pg_multitenant_schemas.rbs
|
|
99
|
+
homepage: https://github.com/rubenpazch/pg_multitenant_schemas
|
|
100
|
+
licenses:
|
|
101
|
+
- MIT
|
|
102
|
+
metadata:
|
|
103
|
+
allowed_push_host: https://rubygems.org
|
|
104
|
+
homepage_uri: https://github.com/rubenpazch/pg_multitenant_schemas
|
|
105
|
+
source_code_uri: https://github.com/rubenpazch/pg_multitenant_schemas
|
|
106
|
+
changelog_uri: https://github.com/rubenpazch/pg_multitenant_schemas/blob/main/CHANGELOG.md
|
|
107
|
+
post_install_message:
|
|
108
|
+
rdoc_options: []
|
|
109
|
+
require_paths:
|
|
110
|
+
- lib
|
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - ">="
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: 3.1.0
|
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
|
+
requirements:
|
|
118
|
+
- - ">="
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: '0'
|
|
121
|
+
requirements: []
|
|
122
|
+
rubygems_version: 3.3.27
|
|
123
|
+
signing_key:
|
|
124
|
+
specification_version: 4
|
|
125
|
+
summary: PostgreSQL schema-based multitenancy for Rails applications
|
|
126
|
+
test_files: []
|