pg_rls 0.0.1.3 → 0.0.1.4.2
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/Gemfile +1 -1
- data/Gemfile.lock +92 -92
- data/README.md +29 -1
- data/lib/generators/pg_rls/active_record/templates/convert_migration_backport.rb.tt +0 -2
- data/lib/pg_rls/Rakefile +6 -0
- data/lib/pg_rls/database/prepared.rb +22 -7
- data/lib/pg_rls/database/tasks/admin_database.rake +117 -0
- data/lib/pg_rls/errors/tenant_not_found.rb +18 -0
- data/lib/pg_rls/railtie.rb +16 -0
- data/lib/pg_rls/schema/up_statements.rb +1 -0
- data/lib/pg_rls/tenant.rb +7 -3
- data/lib/pg_rls/version.rb +1 -1
- data/lib/pg_rls.rb +21 -7
- metadata +13 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c49344c7e0967e1afe2cf3f982678fcdae6edec8766fa92ed51f644594be84e
|
4
|
+
data.tar.gz: 21812122d43412184edefcc4cbe45ba7a160ff5d335f01de8f4962b20fb6e5e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f423f4793439745830715c5a6058c3703445185dee9e0219ceb68c09a57dcd728ddc758daa35947fef94c0248b7cf075ba73452c9eb2e4ee79e8d8d344ab78d9
|
7
|
+
data.tar.gz: 2ad9bb3bac5e097f708075d44b08755621f2cf8202f6a9894dc7171e5ffd728f072d10f61d9df8aabc72297a453ae065088ddf4e403a16f8bb0fc2e2c1d29f7e
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,66 +1,66 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pg_rls (0.0.1)
|
4
|
+
pg_rls (0.0.1.4.2)
|
5
5
|
bundler (>= 2.2.10)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
actioncable (6.1.
|
11
|
-
actionpack (= 6.1.
|
12
|
-
activesupport (= 6.1.
|
10
|
+
actioncable (6.1.5)
|
11
|
+
actionpack (= 6.1.5)
|
12
|
+
activesupport (= 6.1.5)
|
13
13
|
nio4r (~> 2.0)
|
14
14
|
websocket-driver (>= 0.6.1)
|
15
|
-
actionmailbox (6.1.
|
16
|
-
actionpack (= 6.1.
|
17
|
-
activejob (= 6.1.
|
18
|
-
activerecord (= 6.1.
|
19
|
-
activestorage (= 6.1.
|
20
|
-
activesupport (= 6.1.
|
15
|
+
actionmailbox (6.1.5)
|
16
|
+
actionpack (= 6.1.5)
|
17
|
+
activejob (= 6.1.5)
|
18
|
+
activerecord (= 6.1.5)
|
19
|
+
activestorage (= 6.1.5)
|
20
|
+
activesupport (= 6.1.5)
|
21
21
|
mail (>= 2.7.1)
|
22
|
-
actionmailer (6.1.
|
23
|
-
actionpack (= 6.1.
|
24
|
-
actionview (= 6.1.
|
25
|
-
activejob (= 6.1.
|
26
|
-
activesupport (= 6.1.
|
22
|
+
actionmailer (6.1.5)
|
23
|
+
actionpack (= 6.1.5)
|
24
|
+
actionview (= 6.1.5)
|
25
|
+
activejob (= 6.1.5)
|
26
|
+
activesupport (= 6.1.5)
|
27
27
|
mail (~> 2.5, >= 2.5.4)
|
28
28
|
rails-dom-testing (~> 2.0)
|
29
|
-
actionpack (6.1.
|
30
|
-
actionview (= 6.1.
|
31
|
-
activesupport (= 6.1.
|
29
|
+
actionpack (6.1.5)
|
30
|
+
actionview (= 6.1.5)
|
31
|
+
activesupport (= 6.1.5)
|
32
32
|
rack (~> 2.0, >= 2.0.9)
|
33
33
|
rack-test (>= 0.6.3)
|
34
34
|
rails-dom-testing (~> 2.0)
|
35
35
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
36
|
-
actiontext (6.1.
|
37
|
-
actionpack (= 6.1.
|
38
|
-
activerecord (= 6.1.
|
39
|
-
activestorage (= 6.1.
|
40
|
-
activesupport (= 6.1.
|
36
|
+
actiontext (6.1.5)
|
37
|
+
actionpack (= 6.1.5)
|
38
|
+
activerecord (= 6.1.5)
|
39
|
+
activestorage (= 6.1.5)
|
40
|
+
activesupport (= 6.1.5)
|
41
41
|
nokogiri (>= 1.8.5)
|
42
|
-
actionview (6.1.
|
43
|
-
activesupport (= 6.1.
|
42
|
+
actionview (6.1.5)
|
43
|
+
activesupport (= 6.1.5)
|
44
44
|
builder (~> 3.1)
|
45
45
|
erubi (~> 1.4)
|
46
46
|
rails-dom-testing (~> 2.0)
|
47
47
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
48
|
-
activejob (6.1.
|
49
|
-
activesupport (= 6.1.
|
48
|
+
activejob (6.1.5)
|
49
|
+
activesupport (= 6.1.5)
|
50
50
|
globalid (>= 0.3.6)
|
51
|
-
activemodel (6.1.
|
52
|
-
activesupport (= 6.1.
|
53
|
-
activerecord (6.1.
|
54
|
-
activemodel (= 6.1.
|
55
|
-
activesupport (= 6.1.
|
56
|
-
activestorage (6.1.
|
57
|
-
actionpack (= 6.1.
|
58
|
-
activejob (= 6.1.
|
59
|
-
activerecord (= 6.1.
|
60
|
-
activesupport (= 6.1.
|
61
|
-
marcel (~> 1.0
|
51
|
+
activemodel (6.1.5)
|
52
|
+
activesupport (= 6.1.5)
|
53
|
+
activerecord (6.1.5)
|
54
|
+
activemodel (= 6.1.5)
|
55
|
+
activesupport (= 6.1.5)
|
56
|
+
activestorage (6.1.5)
|
57
|
+
actionpack (= 6.1.5)
|
58
|
+
activejob (= 6.1.5)
|
59
|
+
activerecord (= 6.1.5)
|
60
|
+
activesupport (= 6.1.5)
|
61
|
+
marcel (~> 1.0)
|
62
62
|
mini_mime (>= 1.1.0)
|
63
|
-
activesupport (6.1.
|
63
|
+
activesupport (6.1.5)
|
64
64
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
65
65
|
i18n (>= 1.6, < 2)
|
66
66
|
minitest (>= 5.1)
|
@@ -68,15 +68,15 @@ GEM
|
|
68
68
|
zeitwerk (~> 2.3)
|
69
69
|
ast (2.4.2)
|
70
70
|
builder (3.2.4)
|
71
|
-
concurrent-ruby (1.1.
|
71
|
+
concurrent-ruby (1.1.10)
|
72
72
|
crass (1.0.6)
|
73
|
-
diff-lcs (1.
|
73
|
+
diff-lcs (1.5.0)
|
74
74
|
erubi (1.10.0)
|
75
|
-
globalid (0.
|
75
|
+
globalid (1.0.0)
|
76
76
|
activesupport (>= 5.0)
|
77
|
-
i18n (1.
|
77
|
+
i18n (1.10.0)
|
78
78
|
concurrent-ruby (~> 1.0)
|
79
|
-
loofah (2.
|
79
|
+
loofah (2.16.0)
|
80
80
|
crass (~> 1.0.2)
|
81
81
|
nokogiri (>= 1.5.9)
|
82
82
|
mail (2.7.1)
|
@@ -84,87 +84,87 @@ GEM
|
|
84
84
|
marcel (1.0.2)
|
85
85
|
method_source (1.0.0)
|
86
86
|
mini_mime (1.1.2)
|
87
|
-
minitest (5.
|
87
|
+
minitest (5.15.0)
|
88
88
|
nio4r (2.5.8)
|
89
|
-
nokogiri (1.
|
89
|
+
nokogiri (1.13.3-x86_64-linux)
|
90
90
|
racc (~> 1.4)
|
91
|
-
parallel (1.
|
92
|
-
parser (3.
|
91
|
+
parallel (1.22.1)
|
92
|
+
parser (3.1.1.0)
|
93
93
|
ast (~> 2.4.1)
|
94
|
-
racc (1.
|
94
|
+
racc (1.6.0)
|
95
95
|
rack (2.2.3)
|
96
96
|
rack-test (1.1.0)
|
97
97
|
rack (>= 1.0, < 3)
|
98
|
-
rails (6.1.
|
99
|
-
actioncable (= 6.1.
|
100
|
-
actionmailbox (= 6.1.
|
101
|
-
actionmailer (= 6.1.
|
102
|
-
actionpack (= 6.1.
|
103
|
-
actiontext (= 6.1.
|
104
|
-
actionview (= 6.1.
|
105
|
-
activejob (= 6.1.
|
106
|
-
activemodel (= 6.1.
|
107
|
-
activerecord (= 6.1.
|
108
|
-
activestorage (= 6.1.
|
109
|
-
activesupport (= 6.1.
|
98
|
+
rails (6.1.5)
|
99
|
+
actioncable (= 6.1.5)
|
100
|
+
actionmailbox (= 6.1.5)
|
101
|
+
actionmailer (= 6.1.5)
|
102
|
+
actionpack (= 6.1.5)
|
103
|
+
actiontext (= 6.1.5)
|
104
|
+
actionview (= 6.1.5)
|
105
|
+
activejob (= 6.1.5)
|
106
|
+
activemodel (= 6.1.5)
|
107
|
+
activerecord (= 6.1.5)
|
108
|
+
activestorage (= 6.1.5)
|
109
|
+
activesupport (= 6.1.5)
|
110
110
|
bundler (>= 1.15.0)
|
111
|
-
railties (= 6.1.
|
111
|
+
railties (= 6.1.5)
|
112
112
|
sprockets-rails (>= 2.0.0)
|
113
113
|
rails-dom-testing (2.0.3)
|
114
114
|
activesupport (>= 4.2.0)
|
115
115
|
nokogiri (>= 1.6)
|
116
116
|
rails-html-sanitizer (1.4.2)
|
117
117
|
loofah (~> 2.3)
|
118
|
-
railties (6.1.
|
119
|
-
actionpack (= 6.1.
|
120
|
-
activesupport (= 6.1.
|
118
|
+
railties (6.1.5)
|
119
|
+
actionpack (= 6.1.5)
|
120
|
+
activesupport (= 6.1.5)
|
121
121
|
method_source
|
122
|
-
rake (>=
|
122
|
+
rake (>= 12.2)
|
123
123
|
thor (~> 1.0)
|
124
|
-
rainbow (3.
|
124
|
+
rainbow (3.1.1)
|
125
125
|
rake (13.0.6)
|
126
|
-
regexp_parser (2.
|
126
|
+
regexp_parser (2.2.1)
|
127
127
|
rexml (3.2.5)
|
128
|
-
rspec (3.
|
129
|
-
rspec-core (~> 3.
|
130
|
-
rspec-expectations (~> 3.
|
131
|
-
rspec-mocks (~> 3.
|
132
|
-
rspec-core (3.
|
133
|
-
rspec-support (~> 3.
|
134
|
-
rspec-expectations (3.
|
128
|
+
rspec (3.11.0)
|
129
|
+
rspec-core (~> 3.11.0)
|
130
|
+
rspec-expectations (~> 3.11.0)
|
131
|
+
rspec-mocks (~> 3.11.0)
|
132
|
+
rspec-core (3.11.0)
|
133
|
+
rspec-support (~> 3.11.0)
|
134
|
+
rspec-expectations (3.11.0)
|
135
135
|
diff-lcs (>= 1.2.0, < 2.0)
|
136
|
-
rspec-support (~> 3.
|
137
|
-
rspec-mocks (3.
|
136
|
+
rspec-support (~> 3.11.0)
|
137
|
+
rspec-mocks (3.11.1)
|
138
138
|
diff-lcs (>= 1.2.0, < 2.0)
|
139
|
-
rspec-support (~> 3.
|
140
|
-
rspec-support (3.
|
141
|
-
rubocop (1.
|
139
|
+
rspec-support (~> 3.11.0)
|
140
|
+
rspec-support (3.11.0)
|
141
|
+
rubocop (1.26.1)
|
142
142
|
parallel (~> 1.10)
|
143
|
-
parser (>= 3.
|
143
|
+
parser (>= 3.1.0.0)
|
144
144
|
rainbow (>= 2.2.2, < 4.0)
|
145
145
|
regexp_parser (>= 1.8, < 3.0)
|
146
146
|
rexml
|
147
|
-
rubocop-ast (>= 1.
|
147
|
+
rubocop-ast (>= 1.16.0, < 2.0)
|
148
148
|
ruby-progressbar (~> 1.7)
|
149
149
|
unicode-display_width (>= 1.4.0, < 3.0)
|
150
|
-
rubocop-ast (1.
|
151
|
-
parser (>= 3.
|
150
|
+
rubocop-ast (1.16.0)
|
151
|
+
parser (>= 3.1.1.0)
|
152
152
|
ruby-progressbar (1.11.0)
|
153
|
-
sprockets (4.0.
|
153
|
+
sprockets (4.0.3)
|
154
154
|
concurrent-ruby (~> 1.0)
|
155
155
|
rack (> 1, < 3)
|
156
|
-
sprockets-rails (3.
|
157
|
-
actionpack (>=
|
158
|
-
activesupport (>=
|
156
|
+
sprockets-rails (3.4.2)
|
157
|
+
actionpack (>= 5.2)
|
158
|
+
activesupport (>= 5.2)
|
159
159
|
sprockets (>= 3.0.0)
|
160
|
-
thor (1.1
|
160
|
+
thor (1.2.1)
|
161
161
|
tzinfo (2.0.4)
|
162
162
|
concurrent-ruby (~> 1.0)
|
163
163
|
unicode-display_width (2.1.0)
|
164
164
|
websocket-driver (0.7.5)
|
165
165
|
websocket-extensions (>= 0.1.0)
|
166
166
|
websocket-extensions (0.1.5)
|
167
|
-
zeitwerk (2.4
|
167
|
+
zeitwerk (2.5.4)
|
168
168
|
|
169
169
|
PLATFORMS
|
170
170
|
x86_64-linux
|
@@ -177,7 +177,7 @@ DEPENDENCIES
|
|
177
177
|
rubocop
|
178
178
|
|
179
179
|
RUBY VERSION
|
180
|
-
ruby 3.
|
180
|
+
ruby 3.1.1p18
|
181
181
|
|
182
182
|
BUNDLED WITH
|
183
|
-
2.
|
183
|
+
2.3.7
|
data/README.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
<!--
|
2
|
+
Title: PgRls Rails
|
3
|
+
Description: rails multitenancy with pg rls
|
4
|
+
Author: dandush03
|
5
|
+
-->
|
6
|
+
<meta name="google-site-verification" content="Mc1vBv8PRYPw_cdd3EiKhF2vlOeIEIk3VYhAg75ertI" />
|
7
|
+
|
1
8
|
[![Contributors][contributors-shield]][contributors-url]
|
2
9
|
[![Forks][forks-shield]][forks-url]
|
3
10
|
[![Stargazers][stars-shield]][stars-url]
|
@@ -77,7 +84,28 @@ You can swtich to another tenant by using
|
|
77
84
|
```ruby
|
78
85
|
PgRls::Tenant.switch :app #=> where app eq tenant name
|
79
86
|
```
|
80
|
-
Don't forget to update how you want `PgRls` to find your tenant, you can set multiple options by modifying `api/config/initializers/pg_rls.rb` `search_methods`
|
87
|
+
Don't forget to update how you want `PgRls` to find your tenant, you can set multiple options by modifying `api/config/initializers/pg_rls.rb` `search_methods`
|
88
|
+
|
89
|
+
You can add the following configuration to your Database Config File to improve performance and remove `PgRls::SecureConnection` from `aplication_record.rb`
|
90
|
+
|
91
|
+
```yml
|
92
|
+
# app/config/database.yml
|
93
|
+
<% def db_username
|
94
|
+
return PgRls::SECURE_USERNAME unless ENV['AS_DB_ADMIN']
|
95
|
+
|
96
|
+
Rails.application.credentials.dig(:database, :server_1, :username)
|
97
|
+
end %>
|
98
|
+
|
99
|
+
...
|
100
|
+
|
101
|
+
development:
|
102
|
+
<<: *default
|
103
|
+
database: example_development
|
104
|
+
username: <%= db_username %> # Apply this to production and all env including tests
|
105
|
+
|
106
|
+
...
|
107
|
+
|
108
|
+
```
|
81
109
|
### Testing
|
82
110
|
|
83
111
|
Many application uses some sort of database cleaner before running thair spec so on each test that we run we'll have an empty state. Usually, those gems clear our user configuration for the database. To solve this issue, we must implement the following:
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
class PgRlsBackport<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
4
4
|
def up
|
5
|
-
PgRls.establish_default_connection
|
6
|
-
|
7
5
|
# Suggested Code:
|
8
6
|
# PgRls.all_tenants do |tenant|
|
9
7
|
# tenant.<%= table_name %>.in_batches(of: 100) do |<%= table_name %>|
|
data/lib/pg_rls/Rakefile
ADDED
@@ -5,16 +5,31 @@ module PgRls
|
|
5
5
|
# Prepare database for test unit
|
6
6
|
module Prepared
|
7
7
|
class << self
|
8
|
-
def grant_user_credentials(name: PgRls::SECURE_USERNAME)
|
9
|
-
return unless Rails.env.test?
|
8
|
+
def grant_user_credentials(name: PgRls::SECURE_USERNAME, password: 'password')
|
9
|
+
return unless Rails.env.test? || PgRls.default_connection?
|
10
10
|
|
11
|
-
PgRls.
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
PgRls.admin_execute <<-SQL
|
12
|
+
DO
|
13
|
+
$do$
|
14
|
+
BEGIN
|
15
|
+
IF NOT EXISTS (
|
16
|
+
SELECT FROM pg_catalog.pg_roles AS r
|
17
|
+
WHERE r.rolname = '#{name}') THEN
|
18
|
+
|
19
|
+
CREATE USER #{name} WITH PASSWORD '#{password}';
|
20
|
+
END IF;
|
21
|
+
END
|
22
|
+
$do$;
|
23
|
+
GRANT USAGE ON SCHEMA public TO #{name};
|
24
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
25
|
+
GRANT SELECT, INSERT, UPDATE, DELETE
|
26
|
+
ON TABLES TO #{name};
|
15
27
|
GRANT SELECT, INSERT, UPDATE, DELETE
|
16
28
|
ON ALL TABLES IN SCHEMA public
|
17
|
-
|
29
|
+
TO #{name};
|
30
|
+
GRANT USAGE, SELECT
|
31
|
+
ON ALL SEQUENCES IN SCHEMA public
|
32
|
+
TO #{name};
|
18
33
|
SQL
|
19
34
|
end
|
20
35
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# OVERIDE RAILS TASK
|
4
|
+
Rake::TaskManager.class_eval do
|
5
|
+
def alias_task(fq_name)
|
6
|
+
new_name = "#{fq_name}:original"
|
7
|
+
@tasks[new_name] = @tasks.delete(fq_name)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def alias_task(fq_name)
|
12
|
+
Rake.application.alias_task(fq_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def override_task(*args, &block)
|
16
|
+
name, _params, _deps = Rake.application.resolve_args(args.dup)
|
17
|
+
fq_name = Rake.application.instance_variable_get(:@scope).to_a.reverse.push(name).join(':')
|
18
|
+
alias_task(fq_name)
|
19
|
+
Rake::Task.define_task(*args, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
namespace :db do
|
23
|
+
override_task create: :load_config do
|
24
|
+
system('AS_DB_ADMIN=true rake db:create:original')
|
25
|
+
end
|
26
|
+
|
27
|
+
override_task drop: :load_config do
|
28
|
+
system('AS_DB_ADMIN=true rake db:drop:original')
|
29
|
+
end
|
30
|
+
|
31
|
+
override_task migrate: :load_config do
|
32
|
+
system('AS_DB_ADMIN=true rake db:migrate:original')
|
33
|
+
end
|
34
|
+
|
35
|
+
override_task rollback: :load_config do
|
36
|
+
system('AS_DB_ADMIN=true rake db:rollback:original')
|
37
|
+
end
|
38
|
+
|
39
|
+
override_task prepare: :load_config do
|
40
|
+
system('AS_DB_ADMIN=true rake db:prepare:original')
|
41
|
+
end
|
42
|
+
|
43
|
+
override_task setup: :load_config do
|
44
|
+
system('AS_DB_ADMIN=true rake db:setup:original')
|
45
|
+
end
|
46
|
+
|
47
|
+
override_task prepare: :load_config do
|
48
|
+
system('AS_DB_ADMIN=true rake db:reset:original')
|
49
|
+
end
|
50
|
+
|
51
|
+
override_task purge: :load_config do
|
52
|
+
system('AS_DB_ADMIN=true rake db:purge:original')
|
53
|
+
end
|
54
|
+
|
55
|
+
override_task abort_if_pending_migrations: :load_config do
|
56
|
+
system('AS_DB_ADMIN=true rake db:abort_if_pending_migrations:original')
|
57
|
+
end
|
58
|
+
|
59
|
+
override_task seed: :load_config do
|
60
|
+
system('AS_DB_ADMIN=true rake db:seed:original')
|
61
|
+
end
|
62
|
+
|
63
|
+
namespace :test do
|
64
|
+
override_task create: :load_config do
|
65
|
+
system('AS_DB_ADMIN=true rake db:test:create:original')
|
66
|
+
end
|
67
|
+
|
68
|
+
override_task drop: :load_config do
|
69
|
+
system('AS_DB_ADMIN=true rake db:test:drop:original')
|
70
|
+
end
|
71
|
+
|
72
|
+
override_task prepare: :load_config do
|
73
|
+
system('AS_DB_ADMIN=true rake db:test:prepare:original')
|
74
|
+
end
|
75
|
+
|
76
|
+
override_task setup: :load_config do
|
77
|
+
system('AS_DB_ADMIN=true rake db:test:setup:original')
|
78
|
+
end
|
79
|
+
|
80
|
+
override_task purge: :load_config do
|
81
|
+
system('AS_DB_ADMIN=true rake db:test:purge:original')
|
82
|
+
end
|
83
|
+
|
84
|
+
override_task load_schema: :load_config do
|
85
|
+
system('AS_DB_ADMIN=true rake db:test:load_schema:original')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
namespace :enviroment do
|
90
|
+
override_task set: :load_config do
|
91
|
+
system('AS_DB_ADMIN=true rake db:enviroment:set:original')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
namespace :schema do
|
96
|
+
override_task load: :load_config do
|
97
|
+
system('AS_DB_ADMIN=true rake db:schema:load:original')
|
98
|
+
PgRls.admin_execute do
|
99
|
+
PgRls.execute <<-SQL
|
100
|
+
DROP ROLE IF EXISTS #{PgRls::SECURE_USERNAME};
|
101
|
+
CREATE USER #{PgRls::SECURE_USERNAME} WITH PASSWORD '#{PgRls.database_configuration['password']}';
|
102
|
+
GRANT ALL PRIVILEGES ON TABLE schema_migrations TO #{PgRls::SECURE_USERNAME};
|
103
|
+
GRANT USAGE ON SCHEMA public TO #{PgRls::SECURE_USERNAME};
|
104
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
105
|
+
GRANT SELECT, INSERT, UPDATE, DELETE
|
106
|
+
ON TABLES TO #{PgRls::SECURE_USERNAME};
|
107
|
+
GRANT SELECT, INSERT, UPDATE, DELETE
|
108
|
+
ON ALL TABLES IN SCHEMA public
|
109
|
+
TO #{PgRls::SECURE_USERNAME};
|
110
|
+
GRANT USAGE, SELECT
|
111
|
+
ON ALL SEQUENCES IN SCHEMA public
|
112
|
+
TO #{PgRls::SECURE_USERNAME};
|
113
|
+
SQL
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module PgRls
|
2
|
+
module Errors
|
3
|
+
class TenantNotFound < StandardError
|
4
|
+
def initialize
|
5
|
+
reset_tenant_id
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
"Tenant Doesn't exist"
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset_tenant_id
|
14
|
+
PgRls.connection_class.connection.execute('RESET rls.tenant_id')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../pg_rls'
|
4
|
+
require 'rails'
|
5
|
+
|
6
|
+
module PgRls
|
7
|
+
# Extend Rails Railties
|
8
|
+
class Railtie < Rails::Railtie
|
9
|
+
railtie_name :my_gem
|
10
|
+
|
11
|
+
rake_tasks do
|
12
|
+
path = File.dirname(__FILE__)
|
13
|
+
Dir.glob("#{path}/database/tasks/**/*.rake").each { |f| load f }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -9,6 +9,7 @@ module PgRls
|
|
9
9
|
DROP ROLE IF EXISTS #{name};
|
10
10
|
CREATE USER #{name} WITH PASSWORD '#{password}';
|
11
11
|
GRANT ALL PRIVILEGES ON TABLE schema_migrations TO #{name};
|
12
|
+
GRANT USAGE ON SCHEMA public TO #{name};
|
12
13
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
13
14
|
GRANT SELECT, INSERT, UPDATE, DELETE
|
14
15
|
ON TABLES TO #{name};
|
data/lib/pg_rls/tenant.rb
CHANGED
@@ -5,11 +5,12 @@ module PgRls
|
|
5
5
|
module Tenant
|
6
6
|
class << self
|
7
7
|
def switch(resource)
|
8
|
+
@fetch = nil
|
8
9
|
connection_adapter = PgRls.connection_class
|
9
10
|
find_tenant(resource)
|
10
11
|
connection_adapter.connection.execute(format('SET rls.tenant_id = %s',
|
11
12
|
connection_adapter.connection.quote(tenant.tenant_id)))
|
12
|
-
"RLS changed to '#{tenant.
|
13
|
+
"RLS changed to '#{tenant.send(@method)}'"
|
13
14
|
rescue StandardError => e
|
14
15
|
puts 'connection was not made'
|
15
16
|
puts @error || e
|
@@ -18,7 +19,7 @@ module PgRls
|
|
18
19
|
attr_reader :tenant
|
19
20
|
|
20
21
|
def fetch
|
21
|
-
@fetch ||=
|
22
|
+
@fetch ||= PgRls.main_model.find_by_tenant_id(
|
22
23
|
PgRls.connection_class.connection.execute(
|
23
24
|
"SELECT current_setting('rls.tenant_id')"
|
24
25
|
).getvalue(0, 0)
|
@@ -31,9 +32,12 @@ module PgRls
|
|
31
32
|
@tenant = nil
|
32
33
|
|
33
34
|
PgRls.search_methods.each do |method|
|
34
|
-
@
|
35
|
+
@method = method
|
36
|
+
@tenant ||= PgRls.main_model.send("find_by_#{method}!", resource)
|
35
37
|
rescue NoMethodError => e
|
36
38
|
@error = e
|
39
|
+
rescue ActiveRecord::RecordNotFound
|
40
|
+
raise PgRls::Errors::TenantNotFound
|
37
41
|
end
|
38
42
|
end
|
39
43
|
end
|
data/lib/pg_rls/version.rb
CHANGED
data/lib/pg_rls.rb
CHANGED
@@ -8,6 +8,8 @@ require_relative 'pg_rls/schema/statements'
|
|
8
8
|
require_relative 'pg_rls/tenant'
|
9
9
|
require_relative 'pg_rls/secure_connection'
|
10
10
|
require_relative 'pg_rls/multi_tenancy'
|
11
|
+
require_relative 'pg_rls/railtie' if defined?(Rails)
|
12
|
+
require_relative 'pg_rls/errors/tenant_not_found'
|
11
13
|
|
12
14
|
# PostgreSQL Row Level Security
|
13
15
|
module PgRls
|
@@ -17,9 +19,9 @@ module PgRls
|
|
17
19
|
class << self
|
18
20
|
extend Forwardable
|
19
21
|
|
20
|
-
WRITER_METHODS = %i[table_name class_name search_methods].freeze
|
22
|
+
WRITER_METHODS = %i[table_name class_name search_methods establish_default_connection].freeze
|
21
23
|
READER_METHODS = %i[
|
22
|
-
connection_class database_configuration execute table_name class_name search_methods
|
24
|
+
connection_class database_configuration execute table_name class_name search_methods establish_default_connection
|
23
25
|
].freeze
|
24
26
|
DELEGATORS_METHODS = %i[
|
25
27
|
connection_class database_configuration execute table_name search_methods
|
@@ -51,8 +53,20 @@ module PgRls
|
|
51
53
|
)
|
52
54
|
end
|
53
55
|
|
54
|
-
def
|
55
|
-
|
56
|
+
def admin_execute(query = nil)
|
57
|
+
self.establish_default_connection = true
|
58
|
+
establish_new_connection
|
59
|
+
return yield if block_given?
|
60
|
+
|
61
|
+
execute(query)
|
62
|
+
ensure
|
63
|
+
self.establish_default_connection = false
|
64
|
+
establish_new_connection
|
65
|
+
end
|
66
|
+
|
67
|
+
def establish_default_connection=(value)
|
68
|
+
ENV['AS_DB_ADMIN'] = value.to_s
|
69
|
+
@default_connection = value
|
56
70
|
end
|
57
71
|
|
58
72
|
def default_connection?
|
@@ -77,12 +91,12 @@ module PgRls
|
|
77
91
|
end
|
78
92
|
|
79
93
|
def execute(query)
|
80
|
-
|
94
|
+
ActiveRecord::Migration.execute(query)
|
81
95
|
end
|
82
96
|
|
83
97
|
def database_configuration
|
84
|
-
|
85
|
-
config['username'] = PgRls::SECURE_USERNAME
|
98
|
+
database_connection_file[Rails.env].tap do |config|
|
99
|
+
config['username'] = PgRls::SECURE_USERNAME unless default_connection?
|
86
100
|
end
|
87
101
|
end
|
88
102
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_rls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.
|
4
|
+
version: 0.0.1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Laloush
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.2
|
19
|
+
version: '2.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.2
|
26
|
+
version: '2.2'
|
27
27
|
description: |2
|
28
28
|
This gem will help you to integrate PostgreSQL RLS to help you develop a great multitenancy application
|
29
29
|
checkout the repository at https://github.com/Dandush03/pg_rls
|
@@ -60,8 +60,12 @@ files:
|
|
60
60
|
- lib/generators/templates/README
|
61
61
|
- lib/generators/templates/pg_rls.rb.tt
|
62
62
|
- lib/pg_rls.rb
|
63
|
+
- lib/pg_rls/Rakefile
|
63
64
|
- lib/pg_rls/database/prepared.rb
|
65
|
+
- lib/pg_rls/database/tasks/admin_database.rake
|
66
|
+
- lib/pg_rls/errors/tenant_not_found.rb
|
64
67
|
- lib/pg_rls/multi_tenancy.rb
|
68
|
+
- lib/pg_rls/railtie.rb
|
65
69
|
- lib/pg_rls/schema/down_statements.rb
|
66
70
|
- lib/pg_rls/schema/statements.rb
|
67
71
|
- lib/pg_rls/schema/up_statements.rb
|
@@ -79,16 +83,16 @@ require_paths:
|
|
79
83
|
- lib
|
80
84
|
required_ruby_version: !ruby/object:Gem::Requirement
|
81
85
|
requirements:
|
82
|
-
- - "
|
86
|
+
- - "~>"
|
83
87
|
- !ruby/object:Gem::Version
|
84
|
-
version: 3.0
|
88
|
+
version: '3.0'
|
85
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
90
|
requirements:
|
87
91
|
- - ">="
|
88
92
|
- !ruby/object:Gem::Version
|
89
93
|
version: '0'
|
90
94
|
requirements: []
|
91
|
-
rubygems_version: 3.
|
95
|
+
rubygems_version: 3.3.7
|
92
96
|
signing_key:
|
93
97
|
specification_version: 4
|
94
98
|
summary: Write a short summary, because RubyGems requires one.
|