activerecord-multi-tenant 1.1.0 → 2.0.0
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/.github/workflows/CI.yml +73 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Appraisals +16 -0
- data/CHANGELOG.md +28 -0
- data/activerecord-multi-tenant.gemspec +1 -2
- data/gemfiles/active_record_5.2.3.gemfile +16 -0
- data/gemfiles/active_record_6.1.gemfile +8 -0
- data/gemfiles/active_record_7.0.gemfile +8 -0
- data/gemfiles/rails_5.2.3.gemfile +16 -0
- data/gemfiles/rails_6.1.gemfile +8 -0
- data/gemfiles/rails_7.0.gemfile +8 -0
- data/lib/activerecord-multi-tenant/arel_visitors_depth_first.rb +200 -0
- data/lib/activerecord-multi-tenant/copy_from_client.rb +2 -2
- data/lib/activerecord-multi-tenant/model_extensions.rb +16 -4
- data/lib/activerecord-multi-tenant/multi_tenant.rb +22 -8
- data/lib/activerecord-multi-tenant/query_rewriter.rb +14 -9
- data/lib/activerecord-multi-tenant/sidekiq.rb +5 -1
- data/lib/activerecord-multi-tenant/version.rb +1 -1
- data/spec/activerecord-multi-tenant/model_extensions_spec.rb +109 -50
- data/spec/activerecord-multi-tenant/query_rewriter_spec.rb +17 -0
- data/spec/activerecord-multi-tenant/record_finding_spec.rb +36 -0
- data/spec/activerecord-multi-tenant/sidekiq_spec.rb +11 -0
- data/spec/schema.rb +51 -4
- data/spec/spec_helper.rb +7 -0
- metadata +14 -25
- data/.travis.yml +0 -32
- data/Gemfile.lock +0 -197
- data/gemfiles/active_record_5.2.gemfile.lock +0 -188
- data/gemfiles/active_record_6.0.gemfile.lock +0 -198
- data/gemfiles/rails_5.2.gemfile.lock +0 -188
- data/gemfiles/rails_6.0.gemfile.lock +0 -198
@@ -70,6 +70,47 @@ describe MultiTenant do
|
|
70
70
|
it { expect(@partition_key_not_model_task.non_model_id).to be 77 }
|
71
71
|
end
|
72
72
|
|
73
|
+
describe 'Changes table_name after multi_tenant called' do
|
74
|
+
before do
|
75
|
+
account_klass.has_many(:posts, anonymous_class: post_klass)
|
76
|
+
post_klass.belongs_to(:account, anonymous_class: account_klass)
|
77
|
+
|
78
|
+
@account1 = account_klass.create! name: 'foo'
|
79
|
+
@account2 = account_klass.create! name: 'bar'
|
80
|
+
|
81
|
+
@post1 = @account1.posts.create! name: 'foobar'
|
82
|
+
@post2 = @account2.posts.create! name: 'baz'
|
83
|
+
|
84
|
+
MultiTenant.current_tenant = @account1
|
85
|
+
@posts = post_klass.all
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:account_klass) do
|
89
|
+
Class.new(Account) do
|
90
|
+
def self.name
|
91
|
+
'Account'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
let(:post_klass) do
|
97
|
+
Class.new(ActiveRecord::Base) do
|
98
|
+
self.table_name = 'unknown'
|
99
|
+
|
100
|
+
multi_tenant(:account)
|
101
|
+
|
102
|
+
self.table_name = 'posts'
|
103
|
+
|
104
|
+
def self.name
|
105
|
+
'Post'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it { expect(@posts.length).to eq(1) }
|
111
|
+
it { expect(@posts).to eq([@post1]) }
|
112
|
+
end
|
113
|
+
|
73
114
|
# Scoping models
|
74
115
|
describe 'Project.all should be scoped to the current tenant if set' do
|
75
116
|
before do
|
@@ -144,6 +185,16 @@ describe MultiTenant do
|
|
144
185
|
end
|
145
186
|
end
|
146
187
|
|
188
|
+
it 'handles belongs_to with optional: true' do
|
189
|
+
MultiTenant.with(account) do
|
190
|
+
sub_task
|
191
|
+
end
|
192
|
+
|
193
|
+
record = sub_task.optional_sub_tasks.create!
|
194
|
+
expect(record.reload.sub_task).to eq(sub_task)
|
195
|
+
expect(record.account_id).to eq(nil)
|
196
|
+
end
|
197
|
+
|
147
198
|
it 'handles has_many through' do
|
148
199
|
MultiTenant.with(account) do
|
149
200
|
expect(project.sub_tasks).to eq [sub_task]
|
@@ -348,9 +399,12 @@ describe MultiTenant do
|
|
348
399
|
end
|
349
400
|
|
350
401
|
it "applies the team_id conditions in the where clause" do
|
351
|
-
|
352
|
-
|
353
|
-
|
402
|
+
option1 = <<-sql.strip
|
403
|
+
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "tasks"."project_id" = 1 AND "sub_tasks"."account_id" = 1 AND "tasks"."account_id" = 1
|
404
|
+
sql
|
405
|
+
option2 = <<-sql.strip
|
406
|
+
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "sub_tasks"."account_id" = 1 AND "tasks"."project_id" = 1 AND "tasks"."account_id" = 1
|
407
|
+
sql
|
354
408
|
|
355
409
|
account1 = Account.create! name: 'Account 1'
|
356
410
|
|
@@ -358,7 +412,7 @@ describe MultiTenant do
|
|
358
412
|
project1 = Project.create! name: 'Project 1'
|
359
413
|
task1 = Task.create! name: 'Task 1', project: project1
|
360
414
|
subtask1 = SubTask.create! task: task1
|
361
|
-
expect(project1.sub_tasks.to_sql).to eq(
|
415
|
+
expect(project1.sub_tasks.to_sql).to eq(option1).or(eq(option2))
|
362
416
|
expect(project1.sub_tasks).to include(subtask1)
|
363
417
|
end
|
364
418
|
|
@@ -373,9 +427,13 @@ describe MultiTenant do
|
|
373
427
|
end
|
374
428
|
|
375
429
|
it "tests joins between distributed and reference table" do
|
376
|
-
|
377
|
-
|
378
|
-
|
430
|
+
option1 = <<-sql.strip
|
431
|
+
SELECT "categories".* FROM "categories" INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id" WHERE "project_categories"."project_id" = 1 AND "project_categories"."account_id" = 1
|
432
|
+
sql
|
433
|
+
option2 = <<-sql.strip
|
434
|
+
SELECT "categories".* FROM "categories" INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id" WHERE "project_categories"."account_id" = 1 AND "project_categories"."project_id" = 1
|
435
|
+
sql
|
436
|
+
|
379
437
|
account1 = Account.create! name: 'Account 1'
|
380
438
|
category1 = Category.create! name: 'Category 1'
|
381
439
|
|
@@ -383,7 +441,7 @@ describe MultiTenant do
|
|
383
441
|
project1 = Project.create! name: 'Project 1'
|
384
442
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
385
443
|
|
386
|
-
expect(project1.categories.to_sql).to eq(
|
444
|
+
expect(project1.categories.to_sql).to eq(option1).or(eq(option2))
|
387
445
|
expect(project1.categories).to include(category1)
|
388
446
|
expect(project1.project_categories).to include(projectcategory)
|
389
447
|
end
|
@@ -412,21 +470,18 @@ describe MultiTenant do
|
|
412
470
|
account1 = Account.create! name: 'Account 1'
|
413
471
|
category1 = Category.create! name: 'Category 1'
|
414
472
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."account_id" = 1 AND "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = 1 LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" AND "project_categories"."account_id" = 1 WHERE "projects"."account_id" = 1
|
422
|
-
sql
|
423
|
-
end
|
473
|
+
option1 = <<-sql.strip
|
474
|
+
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "project_categories"."account_id" = 1 AND "projects"."account_id" = 1 LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" AND "project_categories"."account_id" = 1 WHERE "projects"."account_id" = 1
|
475
|
+
sql
|
476
|
+
option2 = <<-sql.strip
|
477
|
+
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."account_id" = 1 AND "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = 1 LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" AND "project_categories"."account_id" = 1 WHERE "projects"."account_id" = 1
|
478
|
+
sql
|
424
479
|
|
425
480
|
MultiTenant.with(account1) do
|
426
481
|
project1 = Project.create! name: 'Project 1'
|
427
482
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
428
483
|
|
429
|
-
expect(Project.eager_load(:categories).to_sql).to eq(
|
484
|
+
expect(Project.eager_load(:categories).to_sql).to eq(option1).or(eq(option2))
|
430
485
|
|
431
486
|
project = Project.eager_load(:categories).first
|
432
487
|
expect(project.categories).to include(category1)
|
@@ -451,21 +506,18 @@ describe MultiTenant do
|
|
451
506
|
category1 = Category.create! name: 'Category 1'
|
452
507
|
|
453
508
|
MultiTenant.with(account1) do
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."account_id" = 1 AND "projects"."id" = "tasks"."project_id" LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
|
461
|
-
sql
|
462
|
-
end
|
509
|
+
option1 = <<-sql.strip
|
510
|
+
SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "projects"."account_id" = 1 LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
|
511
|
+
sql
|
512
|
+
option2 = <<-sql.strip
|
513
|
+
SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."account_id" = 1 AND "projects"."id" = "tasks"."project_id" LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
|
514
|
+
sql
|
463
515
|
|
464
516
|
project1 = Project.create! name: 'Project 1'
|
465
517
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
466
518
|
|
467
519
|
project1.tasks.create! name: 'baz'
|
468
|
-
expect(Task.joins(:project).joins('LEFT JOIN project_categories pc ON project.category_id = pc.id').to_sql).to eq(
|
520
|
+
expect(Task.joins(:project).joins('LEFT JOIN project_categories pc ON project.category_id = pc.id').to_sql).to eq(option1).or(eq(option2))
|
469
521
|
end
|
470
522
|
|
471
523
|
MultiTenant.without do
|
@@ -485,32 +537,39 @@ describe MultiTenant do
|
|
485
537
|
project2 = Project.create! name: 'Project 2', account: Account.create!(name: 'Account2')
|
486
538
|
|
487
539
|
MultiTenant.with(account) do
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
540
|
+
option1 = <<-sql.strip
|
541
|
+
SELECT "projects".* FROM "projects" WHERE "projects"."account_id" = #{account.id} AND "projects"."id" = $1 LIMIT $2
|
542
|
+
sql
|
543
|
+
option2 = <<-sql.strip
|
544
|
+
SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 AND "projects"."account_id" = #{account.id} LIMIT $2
|
545
|
+
sql
|
546
|
+
option3 = <<-sql.strip
|
547
|
+
SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 AND "projects"."account_id" = #{account.id} LIMIT $2
|
548
|
+
sql
|
549
|
+
|
550
|
+
# Couldn't make the following line pass for some reason, so came up with an uglier alternative
|
551
|
+
# expect(Project).to receive(:find_by_sql).with(eq(option1).or(eq(option2)).or(eq(option3)), any_args).and_call_original
|
552
|
+
expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
|
553
|
+
expect(args[0]).to(eq(option1).or(eq(option2)).or(eq(option3)))
|
554
|
+
m.call(args[0], args[1], preparable:args[2][:preparable])
|
555
|
+
end
|
499
556
|
expect(Project.find(project.id)).to eq(project)
|
500
557
|
end
|
501
558
|
|
502
559
|
MultiTenant.without do
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
560
|
+
option1 = <<-sql.strip
|
561
|
+
SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2
|
562
|
+
sql
|
563
|
+
option2 = <<-sql.strip
|
564
|
+
SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2
|
565
|
+
sql
|
566
|
+
|
567
|
+
# Couldn't make the following line pass for some reason, so came up with an uglier alternative
|
568
|
+
# expect(Project).to receive(:find_by_sql).with(eq(option1).or(eq(option2)), any_args).and_call_original
|
569
|
+
expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
|
570
|
+
expect(args[0]).to(eq(option1).or(eq(option2)))
|
571
|
+
m.call(args[0], args[1], preparable:args[2][:preparable])
|
572
|
+
end
|
514
573
|
expect(Project.find(project2.id)).to eq(project2)
|
515
574
|
end
|
516
575
|
end
|
@@ -98,4 +98,21 @@ describe "Query Rewriter" do
|
|
98
98
|
}.not_to raise_error
|
99
99
|
end
|
100
100
|
end
|
101
|
+
|
102
|
+
context "when joining with a model with a default scope" do
|
103
|
+
let!(:account) { Account.create!(name: "Test Account") }
|
104
|
+
|
105
|
+
it "fetches only records within the default scope" do
|
106
|
+
alive = Domain.create(name: "alive", account: account)
|
107
|
+
deleted = Domain.create(name: "deleted", deleted: true, account: account)
|
108
|
+
page_in_alive_domain = Page.create(name: "alive", account: account, domain: alive)
|
109
|
+
page_in_deleted_domain = Page.create(name: "deleted", account: account, domain: deleted)
|
110
|
+
|
111
|
+
expect(
|
112
|
+
MultiTenant.with(account) do
|
113
|
+
Page.joins(:domain).pluck(:id)
|
114
|
+
end
|
115
|
+
).to eq([page_in_alive_domain.id])
|
116
|
+
end
|
117
|
+
end
|
101
118
|
end
|
@@ -59,4 +59,40 @@ describe MultiTenant, 'Record finding' do
|
|
59
59
|
expect(second_found).to eq(second_record)
|
60
60
|
end
|
61
61
|
end
|
62
|
+
|
63
|
+
context 'model with has_many relation through multi-tenant model' do
|
64
|
+
let(:tenant_1) { Account.create! name: 'Tenant 1' }
|
65
|
+
let(:project_1) { tenant_1.projects.create! }
|
66
|
+
|
67
|
+
let(:tenant_2) { Account.create! name: 'Tenant 2' }
|
68
|
+
let(:project_2) { tenant_2.projects.create! }
|
69
|
+
|
70
|
+
let(:category) { Category.create! name: 'Category' }
|
71
|
+
|
72
|
+
before do
|
73
|
+
ProjectCategory.create! account: tenant_1, name: '1', project: project_1, category: category
|
74
|
+
ProjectCategory.create! account: tenant_2, name: '2', project: project_2, category: category
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'can get model without creating query cache' do
|
78
|
+
MultiTenant.with(tenant_1) do
|
79
|
+
found_category = Project.find(project_1.id).categories.to_a.first
|
80
|
+
expect(found_category).to eq(category)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'can get model for other tenant' do
|
85
|
+
MultiTenant.with(tenant_2) do
|
86
|
+
found_category = Project.find(project_2.id).categories.to_a.first
|
87
|
+
expect(found_category).to eq(category)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'can get model without current_tenant' do
|
92
|
+
MultiTenant.without do
|
93
|
+
found_category = Project.find(project_2.id).categories.to_a.first
|
94
|
+
expect(found_category).to eq(category)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
62
98
|
end
|
@@ -5,6 +5,9 @@ require 'activerecord-multi-tenant/sidekiq'
|
|
5
5
|
describe MultiTenant, 'Sidekiq' do
|
6
6
|
let(:server) { Sidekiq::Middleware::MultiTenant::Server.new }
|
7
7
|
let(:account) { Account.create(name: 'test') }
|
8
|
+
let(:deleted_acount) { Account.create(name: 'deleted') }
|
9
|
+
|
10
|
+
before { deleted_acount.destroy! }
|
8
11
|
|
9
12
|
describe 'server middleware' do
|
10
13
|
it 'sets the multitenant context when provided in message' do
|
@@ -15,6 +18,14 @@ describe MultiTenant, 'Sidekiq' do
|
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
21
|
+
it 'sets the multitenant context (id) even if tenant not found' do
|
22
|
+
server.call(double,{'bogus' => 'message',
|
23
|
+
'multi_tenant' => { 'class' => deleted_acount.class.name, 'id' => deleted_acount.id}},
|
24
|
+
'bogus_queue') do
|
25
|
+
expect(MultiTenant.current_tenant).to eq(deleted_acount.id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
18
29
|
it 'does not set the multitenant context when no tenant provided' do
|
19
30
|
server.call(double, {'bogus' => 'message'}, 'bogus_queue') do
|
20
31
|
expect(MultiTenant.current_tenant).to be_nil
|
data/spec/schema.rb
CHANGED
@@ -34,6 +34,13 @@ ARGV.grep(/\w+_spec\.rb/).empty? && ActiveRecord::Schema.define(version: 1) do
|
|
34
34
|
t.column :type, :string
|
35
35
|
end
|
36
36
|
|
37
|
+
create_table :optional_sub_tasks, force: true do |t|
|
38
|
+
t.references :account, :integer
|
39
|
+
t.column :sub_task_id, :integer
|
40
|
+
t.column :name, :string
|
41
|
+
t.column :type, :string
|
42
|
+
end
|
43
|
+
|
37
44
|
create_table :countries, force: true do |t|
|
38
45
|
t.column :name, :string
|
39
46
|
end
|
@@ -89,10 +96,26 @@ ARGV.grep(/\w+_spec\.rb/).empty? && ActiveRecord::Schema.define(version: 1) do
|
|
89
96
|
t.column :category_id, :integer
|
90
97
|
end
|
91
98
|
|
92
|
-
|
93
99
|
create_table :allowed_places, force: true, id: false do |t|
|
94
|
-
|
95
|
-
|
100
|
+
t.string :account_id, :integer
|
101
|
+
t.string :name, :string
|
102
|
+
end
|
103
|
+
|
104
|
+
create_table :domains, force: true, partition_key: :account_id do |t|
|
105
|
+
t.column :account_id, :integer
|
106
|
+
t.column :name, :string
|
107
|
+
t.column :deleted, :boolean, default: false
|
108
|
+
end
|
109
|
+
|
110
|
+
create_table :pages, force: true, partition_key: :account_id do |t|
|
111
|
+
t.column :account_id, :integer
|
112
|
+
t.column :name, :string
|
113
|
+
t.column :domain_id, :integer
|
114
|
+
end
|
115
|
+
|
116
|
+
create_table :posts, force: true, partition_key: :account_id do |t|
|
117
|
+
t.column :account_id, :integer
|
118
|
+
t.column :name, :string
|
96
119
|
end
|
97
120
|
|
98
121
|
create_distributed_table :accounts, :id
|
@@ -108,6 +131,9 @@ ARGV.grep(/\w+_spec\.rb/).empty? && ActiveRecord::Schema.define(version: 1) do
|
|
108
131
|
create_distributed_table :uuid_records, :organization_id
|
109
132
|
create_distributed_table :project_categories, :account_id
|
110
133
|
create_distributed_table :allowed_places, :account_id
|
134
|
+
create_distributed_table :domains, :account_id
|
135
|
+
create_distributed_table :pages, :account_id
|
136
|
+
create_distributed_table :posts, :account_id
|
111
137
|
create_reference_table :categories
|
112
138
|
end
|
113
139
|
|
@@ -115,6 +141,7 @@ class Account < ActiveRecord::Base
|
|
115
141
|
multi_tenant :account
|
116
142
|
has_many :projects
|
117
143
|
has_one :manager, inverse_of: :account
|
144
|
+
has_many :optional_sub_tasks
|
118
145
|
end
|
119
146
|
|
120
147
|
class Project < ActiveRecord::Base
|
@@ -146,6 +173,15 @@ class SubTask < ActiveRecord::Base
|
|
146
173
|
multi_tenant :account
|
147
174
|
belongs_to :task
|
148
175
|
has_one :project, through: :task
|
176
|
+
has_many :optional_sub_tasks
|
177
|
+
end
|
178
|
+
|
179
|
+
with_belongs_to_required_by_default do
|
180
|
+
class OptionalSubTask < ActiveRecord::Base
|
181
|
+
multi_tenant :account, optional: true
|
182
|
+
belongs_to :account, optional: true
|
183
|
+
belongs_to :sub_task
|
184
|
+
end
|
149
185
|
end
|
150
186
|
|
151
187
|
class StiSubTask < SubTask
|
@@ -185,6 +221,7 @@ class Comment < ActiveRecord::Base
|
|
185
221
|
end
|
186
222
|
|
187
223
|
class Organization < ActiveRecord::Base
|
224
|
+
multi_tenant :organization
|
188
225
|
has_many :uuid_records
|
189
226
|
end
|
190
227
|
|
@@ -204,7 +241,17 @@ class ProjectCategory < ActiveRecord::Base
|
|
204
241
|
belongs_to :account
|
205
242
|
end
|
206
243
|
|
207
|
-
|
208
244
|
class AllowedPlace < ActiveRecord::Base
|
209
245
|
multi_tenant :account
|
210
246
|
end
|
247
|
+
|
248
|
+
class Domain < ActiveRecord::Base
|
249
|
+
multi_tenant :account
|
250
|
+
has_many :pages
|
251
|
+
default_scope { where(deleted: false) }
|
252
|
+
end
|
253
|
+
|
254
|
+
class Page < ActiveRecord::Base
|
255
|
+
multi_tenant :account
|
256
|
+
belongs_to :domain
|
257
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -46,4 +46,11 @@ def uses_prepared_statements?
|
|
46
46
|
ActiveRecord::Base.connection.prepared_statements
|
47
47
|
end
|
48
48
|
|
49
|
+
def with_belongs_to_required_by_default(&block)
|
50
|
+
default_value = ActiveRecord::Base.belongs_to_required_by_default
|
51
|
+
ActiveRecord::Base.belongs_to_required_by_default = true
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
ActiveRecord::Base.belongs_to_required_by_default = default_value
|
55
|
+
end
|
49
56
|
require 'schema'
|
metadata
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-multi-tenant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Citus Data
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: request_store
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.0.5
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 1.0.5
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rails
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - ">="
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
19
|
+
version: '5.2'
|
34
20
|
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
24
|
- - ">="
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
26
|
+
version: '5.2'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rspec
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,27 +142,30 @@ executables: []
|
|
156
142
|
extensions: []
|
157
143
|
extra_rdoc_files: []
|
158
144
|
files:
|
145
|
+
- ".github/workflows/CI.yml"
|
159
146
|
- ".gitignore"
|
160
|
-
- ".
|
147
|
+
- ".rspec"
|
161
148
|
- Appraisals
|
162
149
|
- CHANGELOG.md
|
163
150
|
- Gemfile
|
164
|
-
- Gemfile.lock
|
165
151
|
- LICENSE
|
166
152
|
- README.md
|
167
153
|
- Rakefile
|
168
154
|
- activerecord-multi-tenant.gemspec
|
169
155
|
- docker-compose.yml
|
170
156
|
- gemfiles/.bundle/config
|
157
|
+
- gemfiles/active_record_5.2.3.gemfile
|
171
158
|
- gemfiles/active_record_5.2.gemfile
|
172
|
-
- gemfiles/active_record_5.2.gemfile.lock
|
173
159
|
- gemfiles/active_record_6.0.gemfile
|
174
|
-
- gemfiles/active_record_6.
|
160
|
+
- gemfiles/active_record_6.1.gemfile
|
161
|
+
- gemfiles/active_record_7.0.gemfile
|
162
|
+
- gemfiles/rails_5.2.3.gemfile
|
175
163
|
- gemfiles/rails_5.2.gemfile
|
176
|
-
- gemfiles/rails_5.2.gemfile.lock
|
177
164
|
- gemfiles/rails_6.0.gemfile
|
178
|
-
- gemfiles/rails_6.
|
165
|
+
- gemfiles/rails_6.1.gemfile
|
166
|
+
- gemfiles/rails_7.0.gemfile
|
179
167
|
- lib/activerecord-multi-tenant.rb
|
168
|
+
- lib/activerecord-multi-tenant/arel_visitors_depth_first.rb
|
180
169
|
- lib/activerecord-multi-tenant/controller_extensions.rb
|
181
170
|
- lib/activerecord-multi-tenant/copy_from_client.rb
|
182
171
|
- lib/activerecord-multi-tenant/fast_truncate.rb
|
@@ -221,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
221
210
|
- !ruby/object:Gem::Version
|
222
211
|
version: '0'
|
223
212
|
requirements: []
|
224
|
-
rubygems_version: 3.
|
213
|
+
rubygems_version: 3.2.32
|
225
214
|
signing_key:
|
226
215
|
specification_version: 4
|
227
216
|
summary: ActiveRecord/Rails integration for multi-tenant databases, in particular
|
data/.travis.yml
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
sudo: required
|
2
|
-
cache: bundler
|
3
|
-
|
4
|
-
language: ruby
|
5
|
-
|
6
|
-
rvm:
|
7
|
-
- 2.5.8
|
8
|
-
- 2.6.4
|
9
|
-
- 2.7.1
|
10
|
-
|
11
|
-
gemfile:
|
12
|
-
- gemfiles/rails_5.2.gemfile
|
13
|
-
- gemfiles/rails_6.0.gemfile
|
14
|
-
- gemfiles/active_record_5.2.gemfile
|
15
|
-
- gemfiles/active_record_6.0.gemfile
|
16
|
-
|
17
|
-
env:
|
18
|
-
- PREPARED_STATEMENTS=0
|
19
|
-
- PREPARED_STATEMENTS=1
|
20
|
-
|
21
|
-
matrix:
|
22
|
-
fast_finish: true
|
23
|
-
|
24
|
-
services:
|
25
|
-
- docker
|
26
|
-
|
27
|
-
before_install:
|
28
|
-
- docker-compose up -d
|
29
|
-
- gem install bundler -v 2.1.4
|
30
|
-
|
31
|
-
script:
|
32
|
-
- bundle exec rake spec
|