pg_multitenant_schemas 0.2.2 → 0.3.6
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/.agent.md +54 -0
- data/.rubocop.yml +7 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +58 -2
- data/DELIVERY_SUMMARY.md +318 -0
- data/GITHUB_ACTIONS_QUICK_START.md +110 -0
- data/GITHUB_ACTIONS_SETUP.md +313 -0
- data/GITHUB_ACTIONS_SUMMARY.md +231 -0
- data/LICENSE.txt +1 -1
- data/LOCAL_TESTING_SUMMARY.md +30 -13
- data/README.md +4 -4
- data/READY_TO_RELEASE.md +308 -0
- data/RELEASE_NOTES.md +194 -0
- data/RELEASE_STEPS.md +122 -0
- data/WORKFLOW_FIXES.md +188 -0
- data/docs/index.html +929 -0
- data/docs/testing_rails_tasks.md +128 -0
- data/lib/pg_multitenant_schemas/configuration.rb +7 -1
- data/lib/pg_multitenant_schemas/context.rb +92 -3
- data/lib/pg_multitenant_schemas/migration_schema_operations.rb +99 -5
- data/lib/pg_multitenant_schemas/migrator.rb +66 -9
- data/lib/pg_multitenant_schemas/rails/controller_concern.rb +81 -6
- data/lib/pg_multitenant_schemas/rails/generators/install_generator.rb +27 -0
- data/lib/pg_multitenant_schemas/rails/generators/tenant_migration_generator.rb +30 -0
- data/lib/pg_multitenant_schemas/rails/model_concern.rb +3 -3
- data/lib/pg_multitenant_schemas/rails/railtie.rb +31 -1
- data/lib/pg_multitenant_schemas/schema_switcher.rb +107 -7
- data/lib/pg_multitenant_schemas/tasks/tenant_tasks.rake +0 -3
- data/lib/pg_multitenant_schemas/tenant_resolver.rb +3 -3
- data/lib/pg_multitenant_schemas/ui/app/assets/stylesheets/pg_multitenant_schemas/ui/application.css +94 -0
- data/lib/pg_multitenant_schemas/ui/app/controllers/pg_multitenant_schemas/ui/tenants_controller.rb +130 -0
- data/lib/pg_multitenant_schemas/ui/app/views/layouts/pg_multitenant_schemas/ui/application.html.erb +29 -0
- data/lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/index.html.erb +85 -0
- data/lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/migration_status.html.erb +45 -0
- data/lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/new.html.erb +50 -0
- data/lib/pg_multitenant_schemas/ui/config/routes.rb +20 -0
- data/lib/pg_multitenant_schemas/ui/engine.rb +49 -0
- data/lib/pg_multitenant_schemas/ui.rb +9 -0
- data/lib/pg_multitenant_schemas/version.rb +1 -1
- data/lib/pg_multitenant_schemas.rb +155 -29
- data/pg_multitenant_schemas.gemspec +18 -12
- data/pre-release-check.sh +46 -0
- metadata +44 -17
- data/lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake +0 -65
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<%= link_to "← Back to Tenants", "/pg_multitenant_schemas/tenants", class: "btn btn-ghost btn-sm", style: "margin-bottom:1rem;display:inline-flex;" %>
|
|
2
|
+
|
|
3
|
+
<div class="card" style="max-width:480px;">
|
|
4
|
+
<div class="card-header"><h2>New Tenant</h2></div>
|
|
5
|
+
|
|
6
|
+
<%= form_with model: @tenant,
|
|
7
|
+
url: "/pg_multitenant_schemas/tenants",
|
|
8
|
+
local: true,
|
|
9
|
+
style: "padding:1.25rem;display:flex;flex-direction:column;gap:1rem;" do |f| %>
|
|
10
|
+
|
|
11
|
+
<% if @tenant.errors.any? %>
|
|
12
|
+
<div class="flash alert">
|
|
13
|
+
<ul style="list-style:none;">
|
|
14
|
+
<% @tenant.errors.full_messages.each do |msg| %>
|
|
15
|
+
<li>⚠ <%= msg %></li>
|
|
16
|
+
<% end %>
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
19
|
+
<% end %>
|
|
20
|
+
|
|
21
|
+
<div style="display:flex;flex-direction:column;gap:.35rem;">
|
|
22
|
+
<%= f.label :subdomain, "Subdomain / Schema name", style: "font-size:.85rem;font-weight:500;" %>
|
|
23
|
+
<%= f.text_field :subdomain,
|
|
24
|
+
placeholder: "e.g. acme_corp",
|
|
25
|
+
style: "border:1px solid #d1d5db;border-radius:6px;padding:.5rem .75rem;font-size:.9rem;",
|
|
26
|
+
required: true %>
|
|
27
|
+
<small style="color:#6b7280;font-size:.78rem;">Used as the PostgreSQL schema name. Lowercase letters, numbers, underscores only.</small>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div style="display:flex;flex-direction:column;gap:.35rem;">
|
|
31
|
+
<%= f.label :name, "Display name", style: "font-size:.85rem;font-weight:500;" %>
|
|
32
|
+
<%= f.text_field :name,
|
|
33
|
+
placeholder: "e.g. ACME Corporation",
|
|
34
|
+
style: "border:1px solid #d1d5db;border-radius:6px;padding:.5rem .75rem;font-size:.9rem;" %>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div style="display:flex;flex-direction:column;gap:.35rem;">
|
|
38
|
+
<%= f.label :status, "Status", style: "font-size:.85rem;font-weight:500;" %>
|
|
39
|
+
<%= f.select :status,
|
|
40
|
+
[["Active", "active"], ["Trial", "trial"], ["Inactive", "inactive"]],
|
|
41
|
+
{ selected: "active" },
|
|
42
|
+
style: "border:1px solid #d1d5db;border-radius:6px;padding:.5rem .75rem;font-size:.9rem;" %>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div style="display:flex;gap:.6rem;padding-top:.25rem;">
|
|
46
|
+
<%= f.submit "Create Tenant & Provision Schema", class: "btn btn-primary" %>
|
|
47
|
+
<%= link_to "Cancel", "/pg_multitenant_schemas/tenants", class: "btn btn-ghost" %>
|
|
48
|
+
</div>
|
|
49
|
+
<% end %>
|
|
50
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
PgMultitenantSchemas::UI::Engine.routes.draw do
|
|
4
|
+
root to: "tenants#index"
|
|
5
|
+
|
|
6
|
+
resources :tenants, only: %i[index new create destroy] do
|
|
7
|
+
member do
|
|
8
|
+
post :migrate
|
|
9
|
+
get :migration_status
|
|
10
|
+
end
|
|
11
|
+
collection do
|
|
12
|
+
post :migrate_all
|
|
13
|
+
post :switch
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Fallback for API-only apps where Rack::MethodOverride may be absent.
|
|
18
|
+
# Keeps the same path used by RESTful DELETE forms, but accepts POST.
|
|
19
|
+
post "/tenants/:id", to: "tenants#destroy"
|
|
20
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgMultitenantSchemas
|
|
4
|
+
module UI
|
|
5
|
+
# Mountable Rails engine that exposes the tenant management UI.
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
isolate_namespace PgMultitenantSchemas::UI
|
|
8
|
+
|
|
9
|
+
# Tell Rails where this engine's app/ directory lives
|
|
10
|
+
config.root = "#{File.expand_path("../../..", __dir__)}/lib/pg_multitenant_schemas/ui"
|
|
11
|
+
|
|
12
|
+
# Fix Zeitwerk inflection: 'ui' directory should map to 'UI' constant
|
|
13
|
+
initializer "pg_multitenant_schemas.ui.inflections", before: :load_config_initializers do
|
|
14
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
15
|
+
inflect.acronym "UI"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
initializer "pg_multitenant_schemas.ui.middleware" do |app|
|
|
20
|
+
# Ensure cookies and session middleware are available for cookie-based schema switching
|
|
21
|
+
# Only in development mode to support schema switching between dashboard and main app
|
|
22
|
+
if ::Rails.env.development?
|
|
23
|
+
# Try to add middleware, but don't fail if it's already there
|
|
24
|
+
begin
|
|
25
|
+
app.config.middleware.insert_before 0, ActionDispatch::Cookies
|
|
26
|
+
rescue StandardError
|
|
27
|
+
# Middleware may already exist, that's fine
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
begin
|
|
31
|
+
app.config.middleware.insert_before 1, ActionDispatch::Session::CookieStore, key: "_pg_multitenant_session"
|
|
32
|
+
rescue StandardError
|
|
33
|
+
# Middleware may already exist, that's fine
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
begin
|
|
37
|
+
app.config.middleware.insert_before 2, ActionDispatch::Flash
|
|
38
|
+
rescue StandardError
|
|
39
|
+
# Middleware may already exist, that's fine
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
initializer "pg_multitenant_schemas.ui.assets" do |app|
|
|
45
|
+
app.config.assets.precompile += %w[pg_multitenant_schemas/ui/application.css] if app.config.respond_to?(:assets)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -1,38 +1,164 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# frozen_string_li# PgMultitenantSchemas provides modern PostgreSQL schema-based multitenancy functionality.
|
|
4
|
-
# Built for Rails 8+ and Ruby 3.4+, it allows switching between different PostgreSQL schemas
|
|
5
|
-
# to achieve secure tenant isolation while maintaining high performance and developer experience.al: true
|
|
6
|
-
|
|
7
|
-
require "active_support/core_ext/module/delegation"
|
|
8
|
-
require "active_support/core_ext/object/blank"
|
|
9
|
-
require_relative "pg_multitenant_schemas/version"
|
|
10
|
-
require_relative "pg_multitenant_schemas/errors"
|
|
11
|
-
require_relative "pg_multitenant_schemas/configuration"
|
|
12
|
-
require_relative "pg_multitenant_schemas/context"
|
|
13
|
-
require_relative "pg_multitenant_schemas/schema_switcher"
|
|
14
|
-
require_relative "pg_multitenant_schemas/tenant_resolver"
|
|
15
|
-
require_relative "pg_multitenant_schemas/migrator"
|
|
16
|
-
|
|
17
|
-
# Rails integration (Rails 8+ required)
|
|
18
|
-
if defined?(Rails)
|
|
19
|
-
require_relative "pg_multitenant_schemas/rails/controller_concern"
|
|
20
|
-
require_relative "pg_multitenant_schemas/rails/model_concern"
|
|
21
|
-
require_relative "pg_multitenant_schemas/rails/railtie"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
3
|
# PgMultitenantSchemas provides modern PostgreSQL schema-based multitenancy functionality.
|
|
4
|
+
#
|
|
25
5
|
# Built for Rails 8+ and Ruby 3.3+, it allows switching between different PostgreSQL schemas
|
|
26
6
|
# to achieve secure tenant isolation while maintaining high performance and developer experience.
|
|
7
|
+
#
|
|
8
|
+
# @example Basic usage
|
|
9
|
+
# tenant = Tenant.find(1)
|
|
10
|
+
# PgMultitenantSchemas.switch_to_tenant(tenant)
|
|
11
|
+
# # All queries now use tenant's schema
|
|
12
|
+
#
|
|
13
|
+
# @example Block-based context
|
|
14
|
+
# PgMultitenantSchemas.with_tenant(tenant) do
|
|
15
|
+
# User.all # Queries tenant's schema
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# @see PgMultitenantSchemas::Context
|
|
19
|
+
# @see PgMultitenantSchemas::SchemaSwitcher
|
|
20
|
+
# @see PgMultitenantSchemas::Migrator
|
|
27
21
|
module PgMultitenantSchemas
|
|
22
|
+
require "active_support/core_ext/module/delegation"
|
|
23
|
+
require "active_support/core_ext/object/blank"
|
|
24
|
+
require_relative "pg_multitenant_schemas/version"
|
|
25
|
+
require_relative "pg_multitenant_schemas/errors"
|
|
26
|
+
require_relative "pg_multitenant_schemas/configuration"
|
|
27
|
+
require_relative "pg_multitenant_schemas/context"
|
|
28
|
+
require_relative "pg_multitenant_schemas/schema_switcher"
|
|
29
|
+
require_relative "pg_multitenant_schemas/tenant_resolver"
|
|
30
|
+
require_relative "pg_multitenant_schemas/migrator"
|
|
31
|
+
|
|
32
|
+
# Rails integration (Rails 8+ required)
|
|
33
|
+
if defined?(Rails)
|
|
34
|
+
require_relative "pg_multitenant_schemas/rails/controller_concern"
|
|
35
|
+
require_relative "pg_multitenant_schemas/rails/model_concern"
|
|
36
|
+
require_relative "pg_multitenant_schemas/rails/railtie"
|
|
37
|
+
require_relative "pg_multitenant_schemas/ui/engine"
|
|
38
|
+
end
|
|
39
|
+
|
|
28
40
|
class << self
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
# Get the current tenant object
|
|
42
|
+
#
|
|
43
|
+
# @return [Object, nil] The current tenant or nil if not set
|
|
44
|
+
# @see Context.current_tenant
|
|
45
|
+
attr_accessor :current_tenant
|
|
46
|
+
|
|
47
|
+
# Set the current tenant object
|
|
48
|
+
#
|
|
49
|
+
# @param tenant [Object] The tenant to set as current
|
|
50
|
+
# @see Context.current_tenant=
|
|
51
|
+
|
|
52
|
+
# Get the current tenant schema name
|
|
53
|
+
#
|
|
54
|
+
# @return [String] The current schema name
|
|
55
|
+
# @see Context.current_schema
|
|
56
|
+
attr_accessor :current_schema
|
|
57
|
+
|
|
58
|
+
# Set the current tenant schema name
|
|
59
|
+
#
|
|
60
|
+
# @param schema [String] The schema name to set as current
|
|
61
|
+
# @see Context.current_schema=
|
|
62
|
+
|
|
63
|
+
# Reset the current tenant context
|
|
64
|
+
#
|
|
65
|
+
# @return [void]
|
|
66
|
+
# @see Context.reset!
|
|
67
|
+
def reset!
|
|
68
|
+
Context.reset!
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Switch to a specific schema
|
|
72
|
+
#
|
|
73
|
+
# @param schema_name [String] The schema name to switch to
|
|
74
|
+
# @return [void]
|
|
75
|
+
# @see Context.switch_to_schema
|
|
76
|
+
def switch_to_schema(schema_name)
|
|
77
|
+
Context.switch_to_schema(schema_name)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Switch to a specific tenant's schema
|
|
81
|
+
#
|
|
82
|
+
# @param tenant [Object, String] The tenant object or schema name
|
|
83
|
+
# @return [void]
|
|
84
|
+
# @see Context.switch_to_tenant
|
|
85
|
+
def switch_to_tenant(tenant)
|
|
86
|
+
Context.switch_to_tenant(tenant)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Execute a block within a tenant context
|
|
90
|
+
#
|
|
91
|
+
# @param tenant_or_schema [Object, String] The tenant object or schema name
|
|
92
|
+
# @yield Executes the given block in the tenant's schema context
|
|
93
|
+
# @return [Object] The return value of the block
|
|
94
|
+
# @see Context.with_tenant
|
|
95
|
+
def with_tenant(tenant_or_schema, &)
|
|
96
|
+
Context.with_tenant(tenant_or_schema, &)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Create a new tenant schema
|
|
100
|
+
#
|
|
101
|
+
# @param tenant_or_schema [Object, String] The tenant object or schema name
|
|
102
|
+
# @return [void]
|
|
103
|
+
# @see Context.create_tenant_schema
|
|
104
|
+
def create_tenant_schema(tenant_or_schema)
|
|
105
|
+
Context.create_tenant_schema(tenant_or_schema)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Drop a tenant schema
|
|
109
|
+
#
|
|
110
|
+
# @param tenant_or_schema [Object, String] The tenant object or schema name
|
|
111
|
+
# @param cascade [Boolean] Whether to drop dependent objects (default: true)
|
|
112
|
+
# @return [void]
|
|
113
|
+
# @see Context.drop_tenant_schema
|
|
114
|
+
def drop_tenant_schema(tenant_or_schema, cascade: true)
|
|
115
|
+
Context.drop_tenant_schema(tenant_or_schema, cascade: cascade)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Extract tenant subdomain from a hostname
|
|
119
|
+
#
|
|
120
|
+
# @param hostname [String] The hostname to extract from
|
|
121
|
+
# @return [String, nil] The extracted subdomain or nil
|
|
122
|
+
# @see TenantResolver.extract_subdomain
|
|
123
|
+
def extract_subdomain(hostname)
|
|
124
|
+
TenantResolver.extract_subdomain(hostname)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Find a tenant by subdomain
|
|
128
|
+
#
|
|
129
|
+
# @param subdomain [String] The subdomain to search for
|
|
130
|
+
# @return [Object, nil] The tenant object or nil if not found
|
|
131
|
+
# @see TenantResolver.find_tenant_by_subdomain
|
|
132
|
+
def find_tenant_by_subdomain(subdomain)
|
|
133
|
+
TenantResolver.find_tenant_by_subdomain(subdomain)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Resolve tenant from Rails request
|
|
137
|
+
#
|
|
138
|
+
# @param request [ActionDispatch::Request] The Rails request object
|
|
139
|
+
# @return [Object, nil] The tenant object or nil if not resolved
|
|
140
|
+
# @see TenantResolver.resolve_tenant_from_request
|
|
141
|
+
def resolve_tenant_from_request(request)
|
|
142
|
+
TenantResolver.resolve_tenant_from_request(request)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Get the current configuration
|
|
147
|
+
#
|
|
148
|
+
# @return [Configuration] The gem configuration object
|
|
149
|
+
def self.configuration
|
|
150
|
+
@configuration ||= Configuration.new
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Configure the gem
|
|
154
|
+
#
|
|
155
|
+
# @yield Yields the configuration object for configuration
|
|
156
|
+
# @example
|
|
157
|
+
# PgMultitenantSchemas.configure do |config|
|
|
158
|
+
# config.tenant_model_class = 'Tenant'
|
|
159
|
+
# config.default_schema = 'public'
|
|
160
|
+
# end
|
|
161
|
+
def self.configure
|
|
162
|
+
yield(configuration) if block_given?
|
|
37
163
|
end
|
|
38
164
|
end
|
|
@@ -5,22 +5,28 @@ require_relative "lib/pg_multitenant_schemas/version"
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "pg_multitenant_schemas"
|
|
7
7
|
spec.version = PgMultitenantSchemas::VERSION
|
|
8
|
-
spec.authors = ["
|
|
9
|
-
spec.email = ["
|
|
8
|
+
spec.authors = ["L BYTE EIRL"]
|
|
9
|
+
spec.email = ["info@lbyte.io"]
|
|
10
10
|
|
|
11
|
-
spec.summary = "Modern PostgreSQL schema-based multitenancy for Rails
|
|
12
|
-
spec.description = "A
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
11
|
+
spec.summary = "Modern PostgreSQL schema-based multitenancy for Rails"
|
|
12
|
+
spec.description = "A production-ready Ruby gem providing PostgreSQL " \
|
|
13
|
+
"schema-based multitenancy with automatic tenant resolution, " \
|
|
14
|
+
"secure isolation, and high performance. Built for Rails 8+ and " \
|
|
15
|
+
"Ruby 4.0+, tested with latest stable versions. Features comprehensive " \
|
|
16
|
+
"test coverage (217 tests, 100% passing), complete YARD " \
|
|
17
|
+
"documentation, and interactive HTML documentation site. Perfect " \
|
|
18
|
+
"for modern SaaS applications with database-level isolation."
|
|
16
19
|
spec.homepage = "https://github.com/rubenpazch/pg_multitenant_schemas"
|
|
17
20
|
spec.license = "MIT"
|
|
18
|
-
spec.required_ruby_version = ">=
|
|
21
|
+
spec.required_ruby_version = ">= 4.0.0"
|
|
19
22
|
|
|
20
23
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
21
24
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
22
25
|
spec.metadata["source_code_uri"] = spec.homepage
|
|
23
26
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
27
|
+
spec.metadata["documentation_uri"] = "https://rubenpazch.github.io/pg_multitenant_schemas"
|
|
28
|
+
spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
|
|
29
|
+
spec.metadata["github_repo"] = "ssh://git@github.com/rubenpazch/pg_multitenant_schemas.git"
|
|
24
30
|
|
|
25
31
|
# Specify which files should be added to the gem when it is released.
|
|
26
32
|
spec.files = Dir.chdir(__dir__) do
|
|
@@ -34,8 +40,8 @@ Gem::Specification.new do |spec|
|
|
|
34
40
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
35
41
|
spec.require_paths = ["lib"]
|
|
36
42
|
|
|
37
|
-
# Runtime dependencies -
|
|
38
|
-
spec.add_dependency "activerecord", ">=
|
|
39
|
-
spec.add_dependency "activesupport", ">=
|
|
40
|
-
spec.add_dependency "pg", "~> 1.
|
|
43
|
+
# Runtime dependencies - Rails 7+ support with Rails 8 optimizations
|
|
44
|
+
spec.add_dependency "activerecord", ">= 7.0", "< 9.0"
|
|
45
|
+
spec.add_dependency "activesupport", ">= 7.0", "< 9.0"
|
|
46
|
+
spec.add_dependency "pg", "~> 1.6"
|
|
41
47
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Pre-Release Checklist for PgMultitenantSchemas
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "🚀 PgMultitenantSchemas Release Preparation"
|
|
8
|
+
echo "==========================================="
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
# Check git status
|
|
12
|
+
echo "📋 Checking git status..."
|
|
13
|
+
git status
|
|
14
|
+
|
|
15
|
+
echo ""
|
|
16
|
+
echo "✅ Pre-Release Checklist"
|
|
17
|
+
echo "======================="
|
|
18
|
+
echo ""
|
|
19
|
+
|
|
20
|
+
# Run tests
|
|
21
|
+
echo "🧪 Running test suite..."
|
|
22
|
+
bundle exec rspec --format=progress 2>&1 | tail -3
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# Check for any syntax errors
|
|
26
|
+
echo "🔍 Checking for syntax errors..."
|
|
27
|
+
bundle exec ruby -c lib/pg_multitenant_schemas.rb > /dev/null && echo "✅ Main module OK"
|
|
28
|
+
bundle exec ruby -c lib/pg_multitenant_schemas/context.rb > /dev/null && echo "✅ Context module OK"
|
|
29
|
+
bundle exec ruby -c lib/pg_multitenant_schemas/schema_switcher.rb > /dev/null && echo "✅ SchemaSwitcher module OK"
|
|
30
|
+
echo ""
|
|
31
|
+
|
|
32
|
+
# Check version
|
|
33
|
+
echo "📌 Current version:"
|
|
34
|
+
grep "VERSION = " lib/pg_multitenant_schemas/version.rb
|
|
35
|
+
echo ""
|
|
36
|
+
|
|
37
|
+
echo "✨ Release checklist completed!"
|
|
38
|
+
echo ""
|
|
39
|
+
echo "📝 Next steps:"
|
|
40
|
+
echo "1. Review changes: git diff"
|
|
41
|
+
echo "2. Stage changes: git add ."
|
|
42
|
+
echo "3. Commit: git commit -m 'Release v0.3.0'"
|
|
43
|
+
echo "4. Create tag: git tag -a v0.3.0 -m 'Release v0.3.0'"
|
|
44
|
+
echo "5. Push: git push && git push --tags"
|
|
45
|
+
echo "6. Build gem: gem build pg_multitenant_schemas.gemspec"
|
|
46
|
+
echo "7. Push to RubyGems: gem push pg_multitenant_schemas-0.3.0.gem"
|
metadata
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_multitenant_schemas
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- L BYTE EIRL
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -15,7 +15,7 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '7.0'
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: '9.0'
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
requirements:
|
|
26
26
|
- - ">="
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: '
|
|
28
|
+
version: '7.0'
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '9.0'
|
|
@@ -35,7 +35,7 @@ dependencies:
|
|
|
35
35
|
requirements:
|
|
36
36
|
- - ">="
|
|
37
37
|
- !ruby/object:Gem::Version
|
|
38
|
-
version: '
|
|
38
|
+
version: '7.0'
|
|
39
39
|
- - "<"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '9.0'
|
|
@@ -45,7 +45,7 @@ dependencies:
|
|
|
45
45
|
requirements:
|
|
46
46
|
- - ">="
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: '
|
|
48
|
+
version: '7.0'
|
|
49
49
|
- - "<"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: '9.0'
|
|
@@ -55,25 +55,28 @@ dependencies:
|
|
|
55
55
|
requirements:
|
|
56
56
|
- - "~>"
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: '1.
|
|
58
|
+
version: '1.6'
|
|
59
59
|
type: :runtime
|
|
60
60
|
prerelease: false
|
|
61
61
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
62
|
requirements:
|
|
63
63
|
- - "~>"
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: '1.
|
|
66
|
-
description: A
|
|
67
|
-
with automatic tenant resolution and
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
version: '1.6'
|
|
66
|
+
description: A production-ready Ruby gem providing PostgreSQL schema-based multitenancy
|
|
67
|
+
with automatic tenant resolution, secure isolation, and high performance. Built
|
|
68
|
+
for Rails 8+ and Ruby 4.0+, tested with latest stable versions. Features comprehensive
|
|
69
|
+
test coverage (217 tests, 100% passing), complete YARD documentation, and interactive
|
|
70
|
+
HTML documentation site. Perfect for modern SaaS applications with database-level
|
|
71
|
+
isolation.
|
|
70
72
|
email:
|
|
71
|
-
-
|
|
73
|
+
- info@lbyte.io
|
|
72
74
|
executables: []
|
|
73
75
|
extensions: []
|
|
74
76
|
extra_rdoc_files: []
|
|
75
77
|
files:
|
|
76
78
|
- ".actrc"
|
|
79
|
+
- ".agent.md"
|
|
77
80
|
- ".env.local.example"
|
|
78
81
|
- ".rspec"
|
|
79
82
|
- ".rubocop.yml"
|
|
@@ -81,17 +84,26 @@ files:
|
|
|
81
84
|
- ".ruby-version"
|
|
82
85
|
- CHANGELOG.md
|
|
83
86
|
- CODE_OF_CONDUCT.md
|
|
87
|
+
- DELIVERY_SUMMARY.md
|
|
88
|
+
- GITHUB_ACTIONS_QUICK_START.md
|
|
89
|
+
- GITHUB_ACTIONS_SETUP.md
|
|
90
|
+
- GITHUB_ACTIONS_SUMMARY.md
|
|
84
91
|
- LICENSE.txt
|
|
85
92
|
- LOCAL_TESTING_SUMMARY.md
|
|
86
93
|
- README.md
|
|
94
|
+
- READY_TO_RELEASE.md
|
|
95
|
+
- RELEASE_NOTES.md
|
|
96
|
+
- RELEASE_STEPS.md
|
|
87
97
|
- Rakefile
|
|
88
98
|
- TESTING_LOCALLY.md
|
|
99
|
+
- WORKFLOW_FIXES.md
|
|
89
100
|
- docs/README.md
|
|
90
101
|
- docs/configuration.md
|
|
91
102
|
- docs/context.md
|
|
92
103
|
- docs/errors.md
|
|
93
104
|
- docs/github_actions_permissions_fix.md
|
|
94
105
|
- docs/github_actions_setup.md
|
|
106
|
+
- docs/index.html
|
|
95
107
|
- docs/integration_testing.md
|
|
96
108
|
- docs/local_workflow_testing.md
|
|
97
109
|
- docs/migrator.md
|
|
@@ -99,6 +111,7 @@ files:
|
|
|
99
111
|
- docs/schema_switcher.md
|
|
100
112
|
- docs/tenant_resolver.md
|
|
101
113
|
- docs/testing.md
|
|
114
|
+
- docs/testing_rails_tasks.md
|
|
102
115
|
- examples/context_management.rb
|
|
103
116
|
- examples/migration_workflow.rb
|
|
104
117
|
- examples/rails_integration/controller_examples.rb
|
|
@@ -113,18 +126,29 @@ files:
|
|
|
113
126
|
- lib/pg_multitenant_schemas/migration_status_reporter.rb
|
|
114
127
|
- lib/pg_multitenant_schemas/migrator.rb
|
|
115
128
|
- lib/pg_multitenant_schemas/rails/controller_concern.rb
|
|
129
|
+
- lib/pg_multitenant_schemas/rails/generators/install_generator.rb
|
|
130
|
+
- lib/pg_multitenant_schemas/rails/generators/tenant_migration_generator.rb
|
|
116
131
|
- lib/pg_multitenant_schemas/rails/model_concern.rb
|
|
117
132
|
- lib/pg_multitenant_schemas/rails/railtie.rb
|
|
118
133
|
- lib/pg_multitenant_schemas/schema_switcher.rb
|
|
119
134
|
- lib/pg_multitenant_schemas/tasks/advanced_tasks.rake
|
|
120
135
|
- lib/pg_multitenant_schemas/tasks/basic_tasks.rake
|
|
121
|
-
- lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake
|
|
122
136
|
- lib/pg_multitenant_schemas/tasks/tenant_tasks.rake
|
|
123
137
|
- lib/pg_multitenant_schemas/tenant_resolver.rb
|
|
124
138
|
- lib/pg_multitenant_schemas/tenant_task_helpers.rb
|
|
139
|
+
- lib/pg_multitenant_schemas/ui.rb
|
|
140
|
+
- lib/pg_multitenant_schemas/ui/app/assets/stylesheets/pg_multitenant_schemas/ui/application.css
|
|
141
|
+
- lib/pg_multitenant_schemas/ui/app/controllers/pg_multitenant_schemas/ui/tenants_controller.rb
|
|
142
|
+
- lib/pg_multitenant_schemas/ui/app/views/layouts/pg_multitenant_schemas/ui/application.html.erb
|
|
143
|
+
- lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/index.html.erb
|
|
144
|
+
- lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/migration_status.html.erb
|
|
145
|
+
- lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/new.html.erb
|
|
146
|
+
- lib/pg_multitenant_schemas/ui/config/routes.rb
|
|
147
|
+
- lib/pg_multitenant_schemas/ui/engine.rb
|
|
125
148
|
- lib/pg_multitenant_schemas/version.rb
|
|
126
149
|
- pg_multitenant_schemas.gemspec
|
|
127
150
|
- pre-push-check.sh
|
|
151
|
+
- pre-release-check.sh
|
|
128
152
|
- rails_integration/app/controllers/application_controller.rb
|
|
129
153
|
- rails_integration/app/models/tenant.rb
|
|
130
154
|
- sig/pg_multitenant_schemas.rbs
|
|
@@ -138,6 +162,9 @@ metadata:
|
|
|
138
162
|
homepage_uri: https://github.com/rubenpazch/pg_multitenant_schemas
|
|
139
163
|
source_code_uri: https://github.com/rubenpazch/pg_multitenant_schemas
|
|
140
164
|
changelog_uri: https://github.com/rubenpazch/pg_multitenant_schemas/blob/main/CHANGELOG.md
|
|
165
|
+
documentation_uri: https://rubenpazch.github.io/pg_multitenant_schemas
|
|
166
|
+
bug_tracker_uri: https://github.com/rubenpazch/pg_multitenant_schemas/issues
|
|
167
|
+
github_repo: ssh://git@github.com/rubenpazch/pg_multitenant_schemas.git
|
|
141
168
|
rdoc_options: []
|
|
142
169
|
require_paths:
|
|
143
170
|
- lib
|
|
@@ -145,14 +172,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
145
172
|
requirements:
|
|
146
173
|
- - ">="
|
|
147
174
|
- !ruby/object:Gem::Version
|
|
148
|
-
version:
|
|
175
|
+
version: 4.0.0
|
|
149
176
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
177
|
requirements:
|
|
151
178
|
- - ">="
|
|
152
179
|
- !ruby/object:Gem::Version
|
|
153
180
|
version: '0'
|
|
154
181
|
requirements: []
|
|
155
|
-
rubygems_version:
|
|
182
|
+
rubygems_version: 4.0.10
|
|
156
183
|
specification_version: 4
|
|
157
|
-
summary: Modern PostgreSQL schema-based multitenancy for Rails
|
|
184
|
+
summary: Modern PostgreSQL schema-based multitenancy for Rails
|
|
158
185
|
test_files: []
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Load individual task files
|
|
4
|
-
Dir[File.join(File.dirname(__FILE__), "*.rake")].each { |file| load file unless file == __FILE__ }
|
|
5
|
-
|
|
6
|
-
require_relative "../tenant_task_helpers"
|
|
7
|
-
|
|
8
|
-
namespace :tenants do
|
|
9
|
-
desc "Create new tenant with attributes (JSON format)"
|
|
10
|
-
task :new, [:attributes] => :environment do |_task, args|
|
|
11
|
-
TenantTaskHelpers.create_tenant_with_attributes(args[:attributes])
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
desc "Drop tenant schema (DANGEROUS)"
|
|
15
|
-
task :drop, [:schema_name] => :environment do |_task, args|
|
|
16
|
-
TenantTaskHelpers.drop_tenant_schema(args[:schema_name])
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
desc "Rollback migrations for a tenant"
|
|
20
|
-
task :rollback, %i[schema_name steps] => :environment do |_task, args|
|
|
21
|
-
steps = (args[:steps] || 1).to_i
|
|
22
|
-
TenantTaskHelpers.rollback_tenant_migrations(args[:schema_name], steps)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Namespace aliases for convenience
|
|
27
|
-
namespace :tenants do
|
|
28
|
-
namespace :db do
|
|
29
|
-
desc "Create tenant schema (alias for tenants:create)"
|
|
30
|
-
task :create, [:schema_name] => "tenants:create"
|
|
31
|
-
|
|
32
|
-
desc "Run tenant migrations (alias for tenants:migrate)"
|
|
33
|
-
task migrate: "tenants:migrate"
|
|
34
|
-
|
|
35
|
-
desc "Check tenant migration status (alias for tenants:status)"
|
|
36
|
-
task status: "tenants:status"
|
|
37
|
-
|
|
38
|
-
desc "Setup all tenants (alias for tenants:setup)"
|
|
39
|
-
task setup: "tenants:setup"
|
|
40
|
-
|
|
41
|
-
desc "Rollback tenant migrations (alias for tenants:rollback)"
|
|
42
|
-
task :rollback, %i[schema_name steps] => "tenants:rollback"
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Legacy namespace for backward compatibility
|
|
47
|
-
namespace :pg_multitenant_schemas do
|
|
48
|
-
desc "DEPRECATED: Use 'tenants:list' instead"
|
|
49
|
-
task list_schemas: "tenants:list"
|
|
50
|
-
|
|
51
|
-
desc "DEPRECATED: Use 'tenants:migrate' instead"
|
|
52
|
-
task migrate_all: "tenants:migrate"
|
|
53
|
-
|
|
54
|
-
desc "DEPRECATED: Use 'tenants:setup' instead"
|
|
55
|
-
task setup: "tenants:setup"
|
|
56
|
-
|
|
57
|
-
desc "DEPRECATED: Use 'tenants:migrate_tenant[schema_name]' instead"
|
|
58
|
-
task :migrate_tenant, [:schema_name] => "tenants:migrate_tenant"
|
|
59
|
-
|
|
60
|
-
desc "DEPRECATED: Use 'tenants:create[schema_name]' instead"
|
|
61
|
-
task :create_schema, [:schema_name] => "tenants:create"
|
|
62
|
-
|
|
63
|
-
desc "DEPRECATED: Use 'tenants:drop[schema_name]' instead"
|
|
64
|
-
task :drop_schema, [:schema_name] => "tenants:drop"
|
|
65
|
-
end
|