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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.agent.md +54 -0
  3. data/.rubocop.yml +7 -1
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +58 -2
  6. data/DELIVERY_SUMMARY.md +318 -0
  7. data/GITHUB_ACTIONS_QUICK_START.md +110 -0
  8. data/GITHUB_ACTIONS_SETUP.md +313 -0
  9. data/GITHUB_ACTIONS_SUMMARY.md +231 -0
  10. data/LICENSE.txt +1 -1
  11. data/LOCAL_TESTING_SUMMARY.md +30 -13
  12. data/README.md +4 -4
  13. data/READY_TO_RELEASE.md +308 -0
  14. data/RELEASE_NOTES.md +194 -0
  15. data/RELEASE_STEPS.md +122 -0
  16. data/WORKFLOW_FIXES.md +188 -0
  17. data/docs/index.html +929 -0
  18. data/docs/testing_rails_tasks.md +128 -0
  19. data/lib/pg_multitenant_schemas/configuration.rb +7 -1
  20. data/lib/pg_multitenant_schemas/context.rb +92 -3
  21. data/lib/pg_multitenant_schemas/migration_schema_operations.rb +99 -5
  22. data/lib/pg_multitenant_schemas/migrator.rb +66 -9
  23. data/lib/pg_multitenant_schemas/rails/controller_concern.rb +81 -6
  24. data/lib/pg_multitenant_schemas/rails/generators/install_generator.rb +27 -0
  25. data/lib/pg_multitenant_schemas/rails/generators/tenant_migration_generator.rb +30 -0
  26. data/lib/pg_multitenant_schemas/rails/model_concern.rb +3 -3
  27. data/lib/pg_multitenant_schemas/rails/railtie.rb +31 -1
  28. data/lib/pg_multitenant_schemas/schema_switcher.rb +107 -7
  29. data/lib/pg_multitenant_schemas/tasks/tenant_tasks.rake +0 -3
  30. data/lib/pg_multitenant_schemas/tenant_resolver.rb +3 -3
  31. data/lib/pg_multitenant_schemas/ui/app/assets/stylesheets/pg_multitenant_schemas/ui/application.css +94 -0
  32. data/lib/pg_multitenant_schemas/ui/app/controllers/pg_multitenant_schemas/ui/tenants_controller.rb +130 -0
  33. data/lib/pg_multitenant_schemas/ui/app/views/layouts/pg_multitenant_schemas/ui/application.html.erb +29 -0
  34. data/lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/index.html.erb +85 -0
  35. data/lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/migration_status.html.erb +45 -0
  36. data/lib/pg_multitenant_schemas/ui/app/views/pg_multitenant_schemas/ui/tenants/new.html.erb +50 -0
  37. data/lib/pg_multitenant_schemas/ui/config/routes.rb +20 -0
  38. data/lib/pg_multitenant_schemas/ui/engine.rb +49 -0
  39. data/lib/pg_multitenant_schemas/ui.rb +9 -0
  40. data/lib/pg_multitenant_schemas/version.rb +1 -1
  41. data/lib/pg_multitenant_schemas.rb +155 -29
  42. data/pg_multitenant_schemas.gemspec +18 -12
  43. data/pre-release-check.sh +46 -0
  44. metadata +44 -17
  45. 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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgMultitenantSchemas
4
+ # Namespace for the mountable UI engine that manages tenants and schemas.
5
+ module UI
6
+ end
7
+ end
8
+
9
+ require_relative "ui/engine"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgMultitenantSchemas
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.6"
5
5
  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
- # Delegate common methods to Context for convenience
30
- delegate :current_tenant, :current_tenant=, :current_schema, :current_schema=,
31
- :reset!, :switch_to_schema, :switch_to_tenant, :with_tenant,
32
- :create_tenant_schema, :drop_tenant_schema, to: :"PgMultitenantSchemas::Context"
33
-
34
- # Delegate tenant resolution to TenantResolver
35
- delegate :extract_subdomain, :find_tenant_by_subdomain, :resolve_tenant_from_request,
36
- to: :"PgMultitenantSchemas::TenantResolver"
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 = ["Ruben Paz"]
9
- spec.email = ["rubenpazchuspe@outlook.com"]
8
+ spec.authors = ["L BYTE EIRL"]
9
+ spec.email = ["info@lbyte.io"]
10
10
 
11
- spec.summary = "Modern PostgreSQL schema-based multitenancy for Rails 8+ applications"
12
- spec.description = "A modern Ruby gem that provides PostgreSQL schema-based multitenancy with automatic tenant " \
13
- "resolution and schema switching. Built for Rails 8+ and Ruby 3.3+, focusing on security, " \
14
- "performance, and developer experience. Perfect for modern SaaS applications requiring " \
15
- "secure tenant isolation."
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 = ">= 3.0.0"
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 - Modern Rails only
38
- spec.add_dependency "activerecord", ">= 8.0", "< 9.0"
39
- spec.add_dependency "activesupport", ">= 8.0", "< 9.0"
40
- spec.add_dependency "pg", "~> 1.5"
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.2.2
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
- - Ruben Paz
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: '8.0'
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: '8.0'
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: '8.0'
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: '8.0'
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.5'
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.5'
66
- description: A modern Ruby gem that provides PostgreSQL schema-based multitenancy
67
- with automatic tenant resolution and schema switching. Built for Rails 8+ and Ruby
68
- 3.3+, focusing on security, performance, and developer experience. Perfect for modern
69
- SaaS applications requiring secure tenant isolation.
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
- - rubenpazchuspe@outlook.com
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: 3.0.0
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: 3.6.7
182
+ rubygems_version: 4.0.10
156
183
  specification_version: 4
157
- summary: Modern PostgreSQL schema-based multitenancy for Rails 8+ applications
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