pg_rls 0.0.1.4 → 0.0.1.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00bc08507823f0659023716267357992118618dd2d69536cf1936f7ffa903961
4
- data.tar.gz: 499004adf0eb1db60bba0e1899a08cc943c64f0e90495016b0acf1a322520731
3
+ metadata.gz: 05d5356859c19958958aaf0c3160e2bafc66a5b3464b542b4087e8684b70dd7c
4
+ data.tar.gz: 2e53e808f31b07293ea6b1071f8e237be72d483964df2d4313c1215973a07fcd
5
5
  SHA512:
6
- metadata.gz: e9ed07f6dfb3477c100eebc4afc2fd72fd639637fc200dd4ce6130e2cbdcb9fb3c6b9c4e5b3955397eb3bd08811542e0c96b954497110d148f048ef8f2583bed
7
- data.tar.gz: 04d74bc577004804a4a5cb039f48dfb32b1bdc8b018aee47729202e6c58bfb7711698b789dfdb575ae715e50c4f78f5a36516841176169481b64bbeafd071dc1
6
+ metadata.gz: b4535bef8f1ed1595cd2639a2db3168c3c0d67b5f94db461bead0d1c00e94fec492e4dbf6a8481baa3f76e102946ec95ab6eed5f2930ecd010feb5d90c1f9da5
7
+ data.tar.gz: 2c14bc491065d684f962a122923fbbba7e40766a02fc870c91d15655ba7a204a1aaec7656e45ae6f11cc2245a56b8327e861dba721a92fc06bb7a62660216952
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in pg_rls.gemspec
6
6
  gemspec
7
- ruby '3.0.2'
7
+ ruby '3.1.1'
8
8
 
9
9
  gem 'rails', '~> 6.1.4', '>= 6.1.4.1'
10
10
 
data/Gemfile.lock CHANGED
@@ -1,66 +1,66 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pg_rls (0.0.1)
5
- bundler (>= 2.2.10)
4
+ pg_rls (0.0.1.4.2)
5
+ bundler (~> 2.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- actioncable (6.1.4.1)
11
- actionpack (= 6.1.4.1)
12
- activesupport (= 6.1.4.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.4.1)
16
- actionpack (= 6.1.4.1)
17
- activejob (= 6.1.4.1)
18
- activerecord (= 6.1.4.1)
19
- activestorage (= 6.1.4.1)
20
- activesupport (= 6.1.4.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.4.1)
23
- actionpack (= 6.1.4.1)
24
- actionview (= 6.1.4.1)
25
- activejob (= 6.1.4.1)
26
- activesupport (= 6.1.4.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.4.1)
30
- actionview (= 6.1.4.1)
31
- activesupport (= 6.1.4.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.4.1)
37
- actionpack (= 6.1.4.1)
38
- activerecord (= 6.1.4.1)
39
- activestorage (= 6.1.4.1)
40
- activesupport (= 6.1.4.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.4.1)
43
- activesupport (= 6.1.4.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.4.1)
49
- activesupport (= 6.1.4.1)
48
+ activejob (6.1.5)
49
+ activesupport (= 6.1.5)
50
50
  globalid (>= 0.3.6)
51
- activemodel (6.1.4.1)
52
- activesupport (= 6.1.4.1)
53
- activerecord (6.1.4.1)
54
- activemodel (= 6.1.4.1)
55
- activesupport (= 6.1.4.1)
56
- activestorage (6.1.4.1)
57
- actionpack (= 6.1.4.1)
58
- activejob (= 6.1.4.1)
59
- activerecord (= 6.1.4.1)
60
- activesupport (= 6.1.4.1)
61
- marcel (~> 1.0.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.4.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.9)
71
+ concurrent-ruby (1.1.10)
72
72
  crass (1.0.6)
73
- diff-lcs (1.4.4)
73
+ diff-lcs (1.5.0)
74
74
  erubi (1.10.0)
75
- globalid (0.5.2)
75
+ globalid (1.0.0)
76
76
  activesupport (>= 5.0)
77
- i18n (1.8.10)
77
+ i18n (1.10.0)
78
78
  concurrent-ruby (~> 1.0)
79
- loofah (2.12.0)
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.14.4)
87
+ minitest (5.15.0)
88
88
  nio4r (2.5.8)
89
- nokogiri (1.12.5-x86_64-linux)
89
+ nokogiri (1.13.3-x86_64-linux)
90
90
  racc (~> 1.4)
91
- parallel (1.21.0)
92
- parser (3.0.2.0)
91
+ parallel (1.22.1)
92
+ parser (3.1.1.0)
93
93
  ast (~> 2.4.1)
94
- racc (1.5.2)
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.4.1)
99
- actioncable (= 6.1.4.1)
100
- actionmailbox (= 6.1.4.1)
101
- actionmailer (= 6.1.4.1)
102
- actionpack (= 6.1.4.1)
103
- actiontext (= 6.1.4.1)
104
- actionview (= 6.1.4.1)
105
- activejob (= 6.1.4.1)
106
- activemodel (= 6.1.4.1)
107
- activerecord (= 6.1.4.1)
108
- activestorage (= 6.1.4.1)
109
- activesupport (= 6.1.4.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.4.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.4.1)
119
- actionpack (= 6.1.4.1)
120
- activesupport (= 6.1.4.1)
118
+ railties (6.1.5)
119
+ actionpack (= 6.1.5)
120
+ activesupport (= 6.1.5)
121
121
  method_source
122
- rake (>= 0.13)
122
+ rake (>= 12.2)
123
123
  thor (~> 1.0)
124
- rainbow (3.0.0)
124
+ rainbow (3.1.1)
125
125
  rake (13.0.6)
126
- regexp_parser (2.1.1)
126
+ regexp_parser (2.2.1)
127
127
  rexml (3.2.5)
128
- rspec (3.10.0)
129
- rspec-core (~> 3.10.0)
130
- rspec-expectations (~> 3.10.0)
131
- rspec-mocks (~> 3.10.0)
132
- rspec-core (3.10.1)
133
- rspec-support (~> 3.10.0)
134
- rspec-expectations (3.10.1)
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.10.0)
137
- rspec-mocks (3.10.2)
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.10.0)
140
- rspec-support (3.10.2)
141
- rubocop (1.22.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.0.0.0)
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.12.0, < 2.0)
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.12.0)
151
- parser (>= 3.0.1.1)
150
+ rubocop-ast (1.16.0)
151
+ parser (>= 3.1.1.0)
152
152
  ruby-progressbar (1.11.0)
153
- sprockets (4.0.2)
153
+ sprockets (4.0.3)
154
154
  concurrent-ruby (~> 1.0)
155
155
  rack (> 1, < 3)
156
- sprockets-rails (3.2.2)
157
- actionpack (>= 4.0)
158
- activesupport (>= 4.0)
156
+ sprockets-rails (3.4.2)
157
+ actionpack (>= 5.2)
158
+ activesupport (>= 5.2)
159
159
  sprockets (>= 3.0.0)
160
- thor (1.1.0)
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.2)
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.0.2p107
180
+ ruby 3.1.1p18
181
181
 
182
182
  BUNDLED WITH
183
- 2.2.27
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:
@@ -20,25 +20,19 @@ module PgRls
20
20
  end
21
21
 
22
22
  def create_tenant_migration_file
23
- return if migration_exist?
24
-
25
- migration_template create_migration_template_path,
23
+ migration_template(create_migration_template_path,
26
24
  "#{migration_path}/#{create_file_sub_name}_#{table_name}.rb",
27
- migration_version: migration_version
25
+ migration_version: migration_version) if creating?
28
26
  end
29
27
 
30
28
  def convert_tenant_migration_file
31
- return unless migration_exist?
32
-
33
- migration_template convert_migration_template_path,
29
+ migration_template(convert_migration_template_path,
34
30
  "#{migration_path}/#{convert_file_sub_name}_#{table_name}.rb",
35
- migration_version: migration_version
31
+ migration_version: migration_version) unless creating?
36
32
 
37
- return if installation_in_progress?
38
-
39
- migration_template 'convert_migration_backport.rb.tt',
33
+ migration_template('convert_migration_backport.rb.tt',
40
34
  "#{migration_path}/pg_rls_backport_#{table_name}.rb",
41
- migration_version: migration_version
35
+ migration_version: migration_version) if installation_in_progress?
42
36
  end
43
37
 
44
38
  def create_model_file
@@ -103,6 +97,10 @@ module PgRls
103
97
  db_migrate_path
104
98
  end
105
99
 
100
+ def creating?
101
+ @creating ||= !migration_exist?
102
+ end
103
+
106
104
  protected
107
105
 
108
106
  def migration_action() = 'add'
@@ -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 %>|
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../pg_rls'
4
+
5
+ path = File.expand_path(__dir__)
6
+ Dir.glob("#{path}/database/tasks/**/*.rake").each { |f| import f }
@@ -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.execute <<-SQL
12
- GRANT USAGE, SELECT
13
- ON ALL SEQUENCES IN SCHEMA public
14
- TO #{name};
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
- TO #{name};
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
@@ -11,7 +11,7 @@ module PgRls
11
11
  include DownStatements
12
12
 
13
13
  def create_rls_tenant_table(table_name, **options, &block)
14
- create_rls_user(password: PgRls.database_configuration['password'])
14
+ create_rls_user(password: PgRls.database_default_configuration[:password])
15
15
  create_rls_setter_function
16
16
  create_rls_blocking_function
17
17
  create_table(table_name, **options, &block)
@@ -41,7 +41,7 @@ module PgRls
41
41
  end
42
42
 
43
43
  def convert_to_rls_tenant_table(table_name, **_options)
44
- create_rls_user(password: PgRls.database_configuration['password'])
44
+ create_rls_user(password: PgRls.database_default_configuration[:password])
45
45
  create_rls_setter_function
46
46
  create_rls_blocking_function
47
47
  add_rls_column_to_tenant_table(table_name)
@@ -6,19 +6,28 @@ module PgRls
6
6
  module UpStatements
7
7
  def create_rls_user(name: PgRls::SECURE_USERNAME, password: 'password')
8
8
  PgRls.execute <<-SQL
9
- DROP ROLE IF EXISTS #{name};
10
- CREATE USER #{name} WITH PASSWORD '#{password}';
11
- GRANT ALL PRIVILEGES ON TABLE schema_migrations TO #{name};
12
- GRANT USAGE ON SCHEMA public TO #{name};
13
- ALTER DEFAULT PRIVILEGES IN SCHEMA public
14
- GRANT SELECT, INSERT, UPDATE, DELETE
15
- ON TABLES TO #{name};
16
- GRANT SELECT, INSERT, UPDATE, DELETE
17
- ON ALL TABLES IN SCHEMA public
18
- TO #{name};
19
- GRANT USAGE, SELECT
20
- ON ALL SEQUENCES IN SCHEMA public
21
- TO #{name};
9
+ DO
10
+ $do$
11
+ BEGIN
12
+ IF NOT EXISTS (
13
+ SELECT FROM pg_catalog.pg_roles -- SELECT list can be empty for this
14
+ WHERE rolname = '#{name}') THEN
15
+
16
+ CREATE USER #{name} WITH PASSWORD '#{password}';
17
+ GRANT ALL PRIVILEGES ON TABLE schema_migrations TO #{name};
18
+ GRANT USAGE ON SCHEMA public TO #{name};
19
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public
20
+ GRANT SELECT, INSERT, UPDATE, DELETE
21
+ ON TABLES TO #{name};
22
+ GRANT SELECT, INSERT, UPDATE, DELETE
23
+ ON ALL TABLES IN SCHEMA public
24
+ TO #{name};
25
+ GRANT USAGE, SELECT
26
+ ON ALL SEQUENCES IN SCHEMA public
27
+ TO #{name};
28
+ END IF;
29
+ END
30
+ $do$;
22
31
  SQL
23
32
  end
24
33
 
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.name}'"
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 ||= tenant.find_by_tenant_id(
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
- @tenant ||= PgRls.main_model.send("find_by_#{method}", resource)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRls
4
- VERSION = '0.0.1.4'
4
+ VERSION = '0.0.1.4.3'
5
5
  end
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 establish_default_connection
55
- @default_connection = true
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,13 +91,17 @@ module PgRls
77
91
  end
78
92
 
79
93
  def execute(query)
80
- @execute = ActiveRecord::Migration.execute(query)
94
+ ActiveRecord::Migration.execute(query)
95
+ end
96
+
97
+ def database_default_configuration
98
+ connection_class.connection.pool.db_config.configuration_hash
81
99
  end
82
100
 
83
101
  def database_configuration
84
- @database_configuration ||= database_connection_file[Rails.env].tap do |config|
85
- config['username'] = PgRls::SECURE_USERNAME
86
- end
102
+ current_configuration = database_default_configuration.deep_dup
103
+ current_configuration.tap { |config| config[:username] = PgRls::SECURE_USERNAME unless default_connection? }
104
+ current_configuration.freeze
87
105
  end
88
106
  end
89
107
  mattr_accessor :table_name
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
4
+ version: 0.0.1.4.3
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-01-08 00:00:00.000000000 Z
11
+ date: 2022-05-17 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.10
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.10
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.0
88
+ version: '3.1'
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.2.22
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.