Skip to content

Commit abd952c

Browse files
committed
Create a specialized database configuration for tenanted: true
1 parent 7b6f25d commit abd952c

File tree

9 files changed

+91
-4
lines changed

9 files changed

+91
-4
lines changed

GUIDE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Documentation:
5050

5151
TODO:
5252
- implement `AR::Tenanted::DatabaseConfigurations::RootConfig` (name?)
53+
- [x] create the specialized RootConfig for `tenanted: true` databases
5354
- [ ] `#database_path_for(tenant_name)`
5455
- [ ] `#tenants` returns all the tenants on disk (for iteration)
5556

@@ -111,6 +112,10 @@ TODO:
111112
- and if not, figure out how to prune unused/timed-out connections
112113
- [ ] we should also look into how to cap the number of connection pools, and prune them
113114

115+
- autoloading and configuration hooks
116+
- [ ] create a zeitwerk loader
117+
- [ ] install some load hooks (where?)
118+
114119

115120
### Tenanting in your application
116121

Gemfile.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ PATH
102102
specs:
103103
active_record-tenanted (0.1.0)
104104
activerecord (>= 8.1.alpha)
105+
railties (>= 8.1.alpha)
105106

106107
GEM
107108
remote: https://rubygems.org/

active_record-tenanted.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ Gem::Specification.new do |spec|
2626
Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
2727
end
2828

29+
spec.add_dependency "railties", ">= 8.1.alpha"
2930
spec.add_dependency "activerecord", ">= 8.1.alpha"
3031
end

lib/active_record/tenanted.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# frozen_string_literal: true
22

3-
require "active_record/tenanted/version"
4-
require "active_record/tenanted/railtie"
3+
require_relative "tenanted/version"
54

65
module ActiveRecord
76
module Tenanted
8-
# Your code goes here...
97
end
108
end
9+
10+
require_relative "tenanted/database_configurations"
11+
12+
require_relative "tenanted/railtie"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
require "active_record/database_configurations"
4+
5+
module ActiveRecord
6+
module Tenanted
7+
module DatabaseConfigurations
8+
class RootConfig < ActiveRecord::DatabaseConfigurations::HashConfig
9+
end
10+
end
11+
end
12+
end

lib/active_record/tenanted/railtie.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ class Railtie < ::Rails::Railtie
66
end
77
end
88
end
9+
10+
ActiveSupport.on_load(:active_record) do
11+
ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, _, config|
12+
next unless config.fetch(:tenanted, false)
13+
ActiveRecord::Tenanted::DatabaseConfigurations::RootConfig.new(env_name, name, config)
14+
end
15+
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
test:
2+
isolated:
3+
tenanted: true
4+
adapter: "sqlite3"
5+
database: "%{storage}/test/isolated/%%{tenant}/main.sqlite3"
6+
migrations_paths: "%{__dir__}/%{scenario}/isolated_migrations"
7+
shared:
8+
adapter: "sqlite3"
9+
database: "%{storage}/test/shared/%%{tenant}/main.sqlite3"
10+
migrations_paths: "%{__dir__}/%{scenario}/shared_migrations"

test/test_helper.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,44 @@
44
ENV["RAILS_ENV"] = "test"
55

66
require "rails"
7-
require "rails/test_help"
7+
require "rails/test_help" # should be before active_record to avoid schema/fixture setup
8+
require "active_record"
89

910
require "minitest/spec"
1011

12+
require_relative "../lib/active_record/tenanted"
13+
1114
module ActiveRecord
1215
module Tenanted
1316
class TestCase < ActiveSupport::TestCase
1417
extend Minitest::Spec::DSL
18+
19+
class << self
20+
def for_each_db_config(&block)
21+
Dir.glob("#{__dir__}/scenarios/*/database.yml").each do |db_config_path|
22+
db_config_name = File.basename(File.dirname(db_config_path))
23+
24+
describe "#{db_config_name} db config" do
25+
setup do
26+
@storage = Dir.mktmpdir(db_config_name)
27+
db_config_yml = sprintf(File.read(db_config_path),
28+
__dir__: __dir__, storage: @storage, scenario: "TODO")
29+
db_config = YAML.load(db_config_yml)
30+
31+
@old_configurations = ActiveRecord::Base.configurations
32+
ActiveRecord::Base.configurations = db_config
33+
end
34+
35+
teardown do
36+
ActiveRecord::Base.configurations = @old_configurations
37+
FileUtils.remove_entry @storage
38+
end
39+
40+
instance_eval(&block)
41+
end
42+
end
43+
end
44+
end
1545
end
1646
end
1747
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
describe ActiveRecord::Tenanted::DatabaseConfigurations do
6+
for_each_db_config do
7+
test "it instantiates a RootConfig for the tenanted database" do
8+
config = ActiveRecord::Base.configurations.configs_for(include_hidden: true)
9+
10+
assert_equal(
11+
{
12+
"isolated" => ActiveRecord::Tenanted::DatabaseConfigurations::RootConfig,
13+
"shared" => ActiveRecord::DatabaseConfigurations::HashConfig,
14+
},
15+
config.each_with_object({}) { |c, h| h[c.name] = c.class }
16+
)
17+
end
18+
end
19+
end

0 commit comments

Comments
 (0)