after_commit_everywhere 1.1.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4425b11aa2651bd44ec24dc839e1338537f087f89c3f19f250d3ad2aeb0fad07
4
- data.tar.gz: 143406ceecd3d9d3e1f7999f8cbb3754c19186036a7b2f47f19996c932048e26
3
+ metadata.gz: e4a45b526cda61ade274b1e038628a0718417047d553c2784242487eca91ad78
4
+ data.tar.gz: ff7c001043feee2cd69d746b0c0fbe9350ebfb608ba94470135280eca878aed1
5
5
  SHA512:
6
- metadata.gz: fdaa287369af57e90b69699fdbd11b687491ea9c938af714e8a68871954b3685e07c4a9ba16939094ea6f082cec84ce351c9354341685f42bcd58bcc0307ee29
7
- data.tar.gz: 5a42c24b63cbdf2d84597e3fa6071d588a76e8821736239a146708dd155a8492dc657c29577022d7072c13ecdcc4d0b1ee22243701d1e1058ebcd13ee6072573
6
+ metadata.gz: 524ecaf8c3598f724d9c02c0faa6c3f2a0fc6ab89d45fa9bc326a5b4a269d479e450120b75c4585ea9b7ce7a0ce8ec005c248838ca84ba6a7003b48cd0c1d76f
7
+ data.tar.gz: 49f603aca07b79763e21a52cb2495a63ea13be07ce646e5e2883e4448c12a9e06079011f50f674db1abc61cc8e93e08fa13bfa2c8b4877cf5940d757931fbde9
@@ -18,15 +18,6 @@ jobs:
18
18
  fail-fast: false
19
19
  matrix:
20
20
  include:
21
- - ruby: '2.5'
22
- activerecord: '4.2'
23
- gemfile: 'activerecord_4_2.gemfile'
24
- - ruby: '2.6'
25
- activerecord: '5.0'
26
- gemfile: 'activerecord_5_0.gemfile'
27
- - ruby: '2.6'
28
- activerecord: '5.1'
29
- gemfile: 'activerecord_5_1.gemfile'
30
21
  - ruby: '2.6'
31
22
  activerecord: '5.2'
32
23
  gemfile: 'activerecord_5_2.gemfile'
@@ -37,6 +28,9 @@ jobs:
37
28
  activerecord: '6.1'
38
29
  gemfile: 'activerecord_6_1.gemfile'
39
30
  - ruby: '3.0'
31
+ activerecord: '7.0'
32
+ gemfile: 'activerecord_7_0.gemfile'
33
+ - ruby: '3.1'
40
34
  activerecord: 'HEAD'
41
35
  gemfile: 'activerecord_master.gemfile'
42
36
  container:
data/Appraisals CHANGED
@@ -31,6 +31,12 @@ appraise "activerecord-6-1" do
31
31
  gem "rspec-rails", "~> 4.0"
32
32
  end
33
33
 
34
+ appraise "activerecord-7-0" do
35
+ gem "activerecord", "~> 7.0.0"
36
+ gem "sqlite3", "~> 1.4"
37
+ gem "rspec-rails", "~> 5.0"
38
+ end
39
+
34
40
  appraise "activerecord-master" do
35
41
  git "https://github.com/rails/rails.git" do
36
42
  gem "rails"
@@ -38,5 +44,5 @@ appraise "activerecord-master" do
38
44
  end
39
45
 
40
46
  gem "sqlite3", "~> 1.4"
41
- gem "rspec-rails", "~> 4.0"
47
+ gem "rspec-rails", "~> 5.0"
42
48
  end
data/CHANGELOG.md CHANGED
@@ -4,7 +4,51 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## 1.2.2 (2022-06-20)
8
+
9
+ ### Fixed
10
+
11
+ - Connection leak from the connection pool when `after_commit` called outside Rails executor without connection checked out *and* some connections were already checked out from another threads.
12
+
13
+ See discussion at [issue #20](https://github.com/Envek/after_commit_everywhere/issues/20) for details.
14
+
15
+ [Pull request #22](https://github.com/Envek/after_commit_everywhere/pull/22) by [@Envek][].
16
+
17
+ ## 1.2.1 (2022-06-10)
18
+
19
+ ### Fixed
20
+
21
+ - Connection leak from the connection pool when `after_commit` called outside Rails executor without connection checked out
22
+
23
+ Usually all invocations of `after_commit` (whether it happens during serving HTTP request in Rails controller or performing job in Sidekiq worker process) are made inside [Rails executor](https://guides.rubyonrails.org/threading_and_code_execution.html#executor) which checks in any connections back to the connection pool that were checked out inside its block.
24
+
25
+ However, in cases when a) `after_commit` was called outside of Rails executor (3-rd party gems or non-Rails apps using ActiveRecord) **and** b) database connection hasn't been checked out yet, then connection will be checked out by `after_commit` implicitly by call to `ActiveRecord::Base.connection` and not checked in back afterwards causing it to _leak_ from the connection pool.
26
+
27
+ But in that case we can be sure that there is no transaction in progress ('cause one need to checkout connection and issue `BEGIN` to it), so we don't need to check it out at all and can fast-forward to `without_tx` action.
28
+
29
+ See discussion at [issue #20](https://github.com/Envek/after_commit_everywhere/issues/20) for details.
30
+
31
+ [Pull request #21](https://github.com/Envek/after_commit_everywhere/pull/21) by [@Envek][].
32
+
33
+ ## 1.2.0 (2022-03-26)
34
+
35
+ ### Added
36
+
37
+ - Allow to change callbacks' behavior when they are called outside transaction:
38
+
39
+ ```ruby
40
+ AfterCommitEverywhere.after_commit(without_tx: :raise) do
41
+ # Will be executed only if was called within transaction
42
+ # Error will be raised otherwise
43
+ end
44
+ ```
45
+
46
+ Available values for `without_tx` keyword argument:
47
+ - `:execute` to execute callback immediately
48
+ - `:warn_and_execute` to print warning and execute immediately
49
+ - `:raise` to raise an exception instead of executing
50
+
51
+ [Pull request #18](https://github.com/Envek/after_commit_everywhere/pull/18) by [@lolripgg][].
8
52
 
9
53
  ## 1.1.0 (2021-08-05)
10
54
 
@@ -54,3 +98,4 @@ See [#11](https://github.com/Envek/after_commit_everywhere/issues/11) for discus
54
98
  [@arjun810]: https://github.com/arjun810 "Arjun Singh"
55
99
  [@joevandyk]: https://github.com/joevandyk "Joe Van Dyk"
56
100
  [@stokarenko]: https://github.com/stokarenko "Sergey Tokarenko"
101
+ [@lolripgg]: https://github.com/lolripgg "James Brewer"
data/Gemfile.lock CHANGED
@@ -1,78 +1,80 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- after_commit_everywhere (1.0.0)
4
+ after_commit_everywhere (1.2.2)
5
5
  activerecord (>= 4.2)
6
6
  activesupport
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actioncable (6.1.4)
12
- actionpack (= 6.1.4)
13
- activesupport (= 6.1.4)
11
+ actioncable (7.0.3)
12
+ actionpack (= 7.0.3)
13
+ activesupport (= 7.0.3)
14
14
  nio4r (~> 2.0)
15
15
  websocket-driver (>= 0.6.1)
16
- actionmailbox (6.1.4)
17
- actionpack (= 6.1.4)
18
- activejob (= 6.1.4)
19
- activerecord (= 6.1.4)
20
- activestorage (= 6.1.4)
21
- activesupport (= 6.1.4)
16
+ actionmailbox (7.0.3)
17
+ actionpack (= 7.0.3)
18
+ activejob (= 7.0.3)
19
+ activerecord (= 7.0.3)
20
+ activestorage (= 7.0.3)
21
+ activesupport (= 7.0.3)
22
22
  mail (>= 2.7.1)
23
- actionmailer (6.1.4)
24
- actionpack (= 6.1.4)
25
- actionview (= 6.1.4)
26
- activejob (= 6.1.4)
27
- activesupport (= 6.1.4)
23
+ net-imap
24
+ net-pop
25
+ net-smtp
26
+ actionmailer (7.0.3)
27
+ actionpack (= 7.0.3)
28
+ actionview (= 7.0.3)
29
+ activejob (= 7.0.3)
30
+ activesupport (= 7.0.3)
28
31
  mail (~> 2.5, >= 2.5.4)
32
+ net-imap
33
+ net-pop
34
+ net-smtp
29
35
  rails-dom-testing (~> 2.0)
30
- actionpack (6.1.4)
31
- actionview (= 6.1.4)
32
- activesupport (= 6.1.4)
33
- rack (~> 2.0, >= 2.0.9)
36
+ actionpack (7.0.3)
37
+ actionview (= 7.0.3)
38
+ activesupport (= 7.0.3)
39
+ rack (~> 2.0, >= 2.2.0)
34
40
  rack-test (>= 0.6.3)
35
41
  rails-dom-testing (~> 2.0)
36
42
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
37
- actiontext (6.1.4)
38
- actionpack (= 6.1.4)
39
- activerecord (= 6.1.4)
40
- activestorage (= 6.1.4)
41
- activesupport (= 6.1.4)
43
+ actiontext (7.0.3)
44
+ actionpack (= 7.0.3)
45
+ activerecord (= 7.0.3)
46
+ activestorage (= 7.0.3)
47
+ activesupport (= 7.0.3)
48
+ globalid (>= 0.6.0)
42
49
  nokogiri (>= 1.8.5)
43
- actionview (6.1.4)
44
- activesupport (= 6.1.4)
50
+ actionview (7.0.3)
51
+ activesupport (= 7.0.3)
45
52
  builder (~> 3.1)
46
53
  erubi (~> 1.4)
47
54
  rails-dom-testing (~> 2.0)
48
55
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
49
- active_attr (0.15.3)
50
- actionpack (>= 3.0.2, < 7.0)
51
- activemodel (>= 3.0.2, < 7.0)
52
- activesupport (>= 3.0.2, < 7.0)
53
- activejob (6.1.4)
54
- activesupport (= 6.1.4)
56
+ activejob (7.0.3)
57
+ activesupport (= 7.0.3)
55
58
  globalid (>= 0.3.6)
56
- activemodel (6.1.4)
57
- activesupport (= 6.1.4)
58
- activerecord (6.1.4)
59
- activemodel (= 6.1.4)
60
- activesupport (= 6.1.4)
61
- activestorage (6.1.4)
62
- actionpack (= 6.1.4)
63
- activejob (= 6.1.4)
64
- activerecord (= 6.1.4)
65
- activesupport (= 6.1.4)
66
- marcel (~> 1.0.0)
59
+ activemodel (7.0.3)
60
+ activesupport (= 7.0.3)
61
+ activerecord (7.0.3)
62
+ activemodel (= 7.0.3)
63
+ activesupport (= 7.0.3)
64
+ activestorage (7.0.3)
65
+ actionpack (= 7.0.3)
66
+ activejob (= 7.0.3)
67
+ activerecord (= 7.0.3)
68
+ activesupport (= 7.0.3)
69
+ marcel (~> 1.0)
67
70
  mini_mime (>= 1.1.0)
68
- activesupport (6.1.4)
71
+ activesupport (7.0.3)
69
72
  concurrent-ruby (~> 1.0, >= 1.0.2)
70
73
  i18n (>= 1.6, < 2)
71
74
  minitest (>= 5.1)
72
75
  tzinfo (~> 2.0)
73
- zeitwerk (~> 2.3)
74
- anyway_config (2.1.0)
75
- ruby-next-core (>= 0.11.0)
76
+ anyway_config (2.3.0)
77
+ ruby-next-core (>= 0.14.0)
76
78
  appraisal (2.4.1)
77
79
  bundler
78
80
  rake
@@ -80,83 +82,99 @@ GEM
80
82
  ast (2.4.2)
81
83
  builder (3.2.4)
82
84
  coderay (1.1.3)
83
- concurrent-ruby (1.1.9)
85
+ concurrent-ruby (1.1.10)
84
86
  crass (1.0.6)
85
- diff-lcs (1.4.4)
87
+ diff-lcs (1.5.0)
88
+ digest (3.1.0)
89
+ dry-initializer (3.1.1)
86
90
  erubi (1.10.0)
87
- globalid (0.5.2)
91
+ globalid (1.0.0)
88
92
  activesupport (>= 5.0)
89
- i18n (1.8.10)
93
+ i18n (1.10.0)
90
94
  concurrent-ruby (~> 1.0)
91
- isolator (0.7.0)
95
+ isolator (0.8.0)
92
96
  sniffer (>= 0.3.1)
93
97
  jaro_winkler (1.5.4)
94
- loofah (2.11.0)
98
+ loofah (2.18.0)
95
99
  crass (~> 1.0.2)
96
100
  nokogiri (>= 1.5.9)
97
101
  mail (2.7.1)
98
102
  mini_mime (>= 0.1.1)
99
- marcel (1.0.1)
103
+ marcel (1.0.2)
100
104
  method_source (1.0.0)
101
- mini_mime (1.1.0)
102
- mini_portile2 (2.6.1)
103
- minitest (5.14.4)
105
+ mini_mime (1.1.2)
106
+ mini_portile2 (2.8.0)
107
+ minitest (5.15.0)
108
+ net-imap (0.2.3)
109
+ digest
110
+ net-protocol
111
+ strscan
112
+ net-pop (0.1.1)
113
+ digest
114
+ net-protocol
115
+ timeout
116
+ net-protocol (0.1.3)
117
+ timeout
118
+ net-smtp (0.3.1)
119
+ digest
120
+ net-protocol
121
+ timeout
104
122
  nio4r (2.5.8)
105
- nokogiri (1.12.2)
106
- mini_portile2 (~> 2.6.1)
123
+ nokogiri (1.13.6)
124
+ mini_portile2 (~> 2.8.0)
107
125
  racc (~> 1.4)
108
- parallel (1.20.1)
109
- parser (3.0.2.0)
126
+ parallel (1.22.1)
127
+ parser (3.1.2.0)
110
128
  ast (~> 2.4.1)
111
129
  pry (0.14.1)
112
130
  coderay (~> 1.1)
113
131
  method_source (~> 1.0)
114
- racc (1.5.2)
115
- rack (2.2.3)
132
+ racc (1.6.0)
133
+ rack (2.2.3.1)
116
134
  rack-test (1.1.0)
117
135
  rack (>= 1.0, < 3)
118
- rails (6.1.4)
119
- actioncable (= 6.1.4)
120
- actionmailbox (= 6.1.4)
121
- actionmailer (= 6.1.4)
122
- actionpack (= 6.1.4)
123
- actiontext (= 6.1.4)
124
- actionview (= 6.1.4)
125
- activejob (= 6.1.4)
126
- activemodel (= 6.1.4)
127
- activerecord (= 6.1.4)
128
- activestorage (= 6.1.4)
129
- activesupport (= 6.1.4)
136
+ rails (7.0.3)
137
+ actioncable (= 7.0.3)
138
+ actionmailbox (= 7.0.3)
139
+ actionmailer (= 7.0.3)
140
+ actionpack (= 7.0.3)
141
+ actiontext (= 7.0.3)
142
+ actionview (= 7.0.3)
143
+ activejob (= 7.0.3)
144
+ activemodel (= 7.0.3)
145
+ activerecord (= 7.0.3)
146
+ activestorage (= 7.0.3)
147
+ activesupport (= 7.0.3)
130
148
  bundler (>= 1.15.0)
131
- railties (= 6.1.4)
132
- sprockets-rails (>= 2.0.0)
149
+ railties (= 7.0.3)
133
150
  rails-dom-testing (2.0.3)
134
151
  activesupport (>= 4.2.0)
135
152
  nokogiri (>= 1.6)
136
- rails-html-sanitizer (1.3.0)
153
+ rails-html-sanitizer (1.4.3)
137
154
  loofah (~> 2.3)
138
- railties (6.1.4)
139
- actionpack (= 6.1.4)
140
- activesupport (= 6.1.4)
155
+ railties (7.0.3)
156
+ actionpack (= 7.0.3)
157
+ activesupport (= 7.0.3)
141
158
  method_source
142
- rake (>= 0.13)
159
+ rake (>= 12.2)
143
160
  thor (~> 1.0)
144
- rainbow (3.0.0)
161
+ zeitwerk (~> 2.5)
162
+ rainbow (3.1.1)
145
163
  rake (13.0.6)
146
164
  rexml (3.2.5)
147
- rspec (3.10.0)
148
- rspec-core (~> 3.10.0)
149
- rspec-expectations (~> 3.10.0)
150
- rspec-mocks (~> 3.10.0)
151
- rspec-core (3.10.1)
152
- rspec-support (~> 3.10.0)
153
- rspec-expectations (3.10.1)
165
+ rspec (3.11.0)
166
+ rspec-core (~> 3.11.0)
167
+ rspec-expectations (~> 3.11.0)
168
+ rspec-mocks (~> 3.11.0)
169
+ rspec-core (3.11.0)
170
+ rspec-support (~> 3.11.0)
171
+ rspec-expectations (3.11.0)
154
172
  diff-lcs (>= 1.2.0, < 2.0)
155
- rspec-support (~> 3.10.0)
156
- rspec-mocks (3.10.2)
173
+ rspec-support (~> 3.11.0)
174
+ rspec-mocks (3.11.1)
157
175
  diff-lcs (>= 1.2.0, < 2.0)
158
- rspec-support (~> 3.10.0)
159
- rspec-rails (5.0.1)
176
+ rspec-support (~> 3.11.0)
177
+ rspec-rails (5.1.2)
160
178
  actionpack (>= 5.2)
161
179
  activesupport (>= 5.2)
162
180
  railties (>= 5.2)
@@ -164,7 +182,7 @@ GEM
164
182
  rspec-expectations (~> 3.10)
165
183
  rspec-mocks (~> 3.10)
166
184
  rspec-support (~> 3.10)
167
- rspec-support (3.10.2)
185
+ rspec-support (3.11.0)
168
186
  rubocop (0.81.0)
169
187
  jaro_winkler (~> 1.5.1)
170
188
  parallel (~> 1.10)
@@ -173,27 +191,22 @@ GEM
173
191
  rexml
174
192
  ruby-progressbar (~> 1.7)
175
193
  unicode-display_width (>= 1.4.0, < 2.0)
176
- ruby-next-core (0.12.0)
194
+ ruby-next-core (0.15.1)
177
195
  ruby-progressbar (1.11.0)
178
- sniffer (0.4.0)
179
- active_attr (>= 0.10.2)
196
+ sniffer (0.5.0)
180
197
  anyway_config (>= 1.0)
181
- sprockets (4.0.2)
182
- concurrent-ruby (~> 1.0)
183
- rack (> 1, < 3)
184
- sprockets-rails (3.2.2)
185
- actionpack (>= 4.0)
186
- activesupport (>= 4.0)
187
- sprockets (>= 3.0.0)
198
+ dry-initializer (~> 3)
188
199
  sqlite3 (1.4.2)
189
- thor (1.1.0)
200
+ strscan (3.0.3)
201
+ thor (1.2.1)
202
+ timeout (0.3.0)
190
203
  tzinfo (2.0.4)
191
204
  concurrent-ruby (~> 1.0)
192
- unicode-display_width (1.7.0)
205
+ unicode-display_width (1.8.0)
193
206
  websocket-driver (0.7.5)
194
207
  websocket-extensions (>= 0.1.0)
195
208
  websocket-extensions (0.1.5)
196
- zeitwerk (2.4.2)
209
+ zeitwerk (2.5.4)
197
210
 
198
211
  PLATFORMS
199
212
  ruby
@@ -212,4 +225,4 @@ DEPENDENCIES
212
225
  sqlite3 (~> 1.3, >= 1.3.6)
213
226
 
214
227
  BUNDLED WITH
215
- 2.2.25
228
+ 2.3.16
data/README.md CHANGED
@@ -119,6 +119,15 @@ Please keep in mind ActiveRecord's [limitations for rolling back nested transact
119
119
 
120
120
  Returns `true` when called inside open transaction, `false` otherwise.
121
121
 
122
+ ### Available callback options
123
+
124
+ - `without_tx` allows to change default callback behavior if called without transaction open.
125
+
126
+ Available values:
127
+ - `:execute` to execute callback immediately
128
+ - `:warn_and_execute` to print warning and execute immediately
129
+ - `:raise` to raise an exception instead of executing
130
+
122
131
  ### FAQ
123
132
 
124
133
  #### Does it works with transactional_test or DatabaseCleaner
@@ -171,7 +180,7 @@ class Post < ActiveRecord::Base
171
180
  end
172
181
  ```
173
182
 
174
- However, if you do something in models that requires defining such ad-hoc transactional callbacks, it may indicate that your models have too many responsibilities and these methods should be extracted to separate secialized layers (service objects, etc).
183
+ However, if you do something in models that requires defining such ad-hoc transactional callbacks, it may indicate that your models have too many responsibilities and these methods should be extracted to separate specialized layers (service objects, etc).
175
184
 
176
185
  ## Development
177
186
 
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 7.0.0"
6
+ gem "sqlite3", "~> 1.4"
7
+ gem "rspec-rails", "~> 5.0"
8
+
9
+ gemspec path: "../"
@@ -8,6 +8,6 @@ git "https://github.com/rails/rails.git" do
8
8
  end
9
9
 
10
10
  gem "sqlite3", "~> 1.4"
11
- gem "rspec-rails", "~> 4.0"
11
+ gem "rspec-rails", "~> 5.0"
12
12
 
13
13
  gemspec path: "../"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AfterCommitEverywhere
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.2"
5
5
  end
@@ -16,34 +16,58 @@ module AfterCommitEverywhere
16
16
  delegate :after_commit, :before_commit, :after_rollback, to: AfterCommitEverywhere
17
17
  delegate :in_transaction?, to: AfterCommitEverywhere
18
18
 
19
+ # Causes {before_commit} and {after_commit} to raise an exception when
20
+ # called outside a transaction.
21
+ RAISE = :raise
22
+ # Causes {before_commit} and {after_commit} to execute the given callback
23
+ # immediately when called outside a transaction.
24
+ EXECUTE = :execute
25
+ # Causes {before_commit} and {after_commit} to log a warning before calling
26
+ # the given callback immediately when called outside a transaction.
27
+ WARN_AND_EXECUTE = :warn_and_execute
28
+
19
29
  class << self
20
30
  # Runs +callback+ after successful commit of outermost transaction for
21
31
  # database +connection+.
22
32
  #
23
- # If called outside transaction it will execute callback immediately.
33
+ # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] Database connection to operate in. Defaults to +ActiveRecord::Base.connection+
34
+ # @param without_tx [Symbol] Determines the behavior of this function when
35
+ # called without an open transaction.
36
+ #
37
+ # Must be one of: {RAISE}, {EXECUTE}, or {WARN_AND_EXECUTE}.
24
38
  #
25
- # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
26
39
  # @param callback [#call] Callback to be executed
27
40
  # @return void
28
- def after_commit(connection: ActiveRecord::Base.connection, &callback)
41
+ def after_commit(
42
+ connection: nil,
43
+ without_tx: EXECUTE,
44
+ &callback
45
+ )
29
46
  register_callback(
30
47
  connection: connection,
31
48
  name: __method__,
32
49
  callback: callback,
33
- no_tx_action: :execute,
50
+ without_tx: without_tx,
34
51
  )
35
52
  end
36
53
 
37
54
  # Runs +callback+ before committing of outermost transaction for +connection+.
38
55
  #
39
- # If called outside transaction it will execute callback immediately.
40
- #
41
56
  # Available only since Ruby on Rails 5.0. See https://github.com/rails/rails/pull/18936
42
57
  #
43
- # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
58
+ # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] Database connection to operate in. Defaults to +ActiveRecord::Base.connection+
59
+ # @param without_tx [Symbol] Determines the behavior of this function when
60
+ # called without an open transaction.
61
+ #
62
+ # Must be one of: {RAISE}, {EXECUTE}, or {WARN_AND_EXECUTE}.
63
+ #
44
64
  # @param callback [#call] Callback to be executed
45
65
  # @return void
46
- def before_commit(connection: ActiveRecord::Base.connection, &callback)
66
+ def before_commit(
67
+ connection: nil,
68
+ without_tx: WARN_AND_EXECUTE,
69
+ &callback
70
+ )
47
71
  if ActiveRecord::VERSION::MAJOR < 5
48
72
  raise NotImplementedError, "#{__method__} works only with Rails 5.0+"
49
73
  end
@@ -52,7 +76,7 @@ module AfterCommitEverywhere
52
76
  connection: connection,
53
77
  name: __method__,
54
78
  callback: callback,
55
- no_tx_action: :warn_and_execute,
79
+ without_tx: without_tx,
56
80
  )
57
81
  end
58
82
 
@@ -62,42 +86,56 @@ module AfterCommitEverywhere
62
86
  # Caveat: do not raise +ActivRecord::Rollback+ in nested transaction block!
63
87
  # See http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions
64
88
  #
65
- # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
89
+ # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] Database connection to operate in. Defaults to +ActiveRecord::Base.connection+
66
90
  # @param callback [#call] Callback to be executed
67
91
  # @return void
68
92
  # @raise [NotInTransaction] if called outside transaction.
69
- def after_rollback(connection: ActiveRecord::Base.connection, &callback)
93
+ def after_rollback(connection: nil, &callback)
70
94
  register_callback(
71
95
  connection: connection,
72
96
  name: __method__,
73
97
  callback: callback,
74
- no_tx_action: :exception,
98
+ without_tx: RAISE,
75
99
  )
76
100
  end
77
101
 
78
102
  # @api private
79
- def register_callback(connection:, name:, no_tx_action:, callback:)
103
+ def register_callback(connection: nil, name:, without_tx:, callback:)
80
104
  raise ArgumentError, "Provide callback to #{name}" unless callback
81
105
 
82
106
  unless in_transaction?(connection)
83
- case no_tx_action
84
- when :warn_and_execute
107
+ case without_tx
108
+ when WARN_AND_EXECUTE
85
109
  warn "#{name}: No transaction open. Executing callback immediately."
86
110
  return callback.call
87
- when :execute
111
+ when EXECUTE
88
112
  return callback.call
89
- when :exception
113
+ when RAISE
90
114
  raise NotInTransaction, "#{name} is useless outside transaction"
115
+ else
116
+ raise ArgumentError, "Invalid \"without_tx\": \"#{without_tx}\""
91
117
  end
92
118
  end
119
+
120
+ connection ||= default_connection
93
121
  wrap = Wrap.new(connection: connection, "#{name}": callback)
94
122
  connection.add_transaction_record(wrap)
95
123
  end
96
124
 
97
125
  # Helper method to determine whether we're currently in transaction or not
98
- def in_transaction?(connection = ActiveRecord::Base.connection)
126
+ def in_transaction?(connection = nil)
127
+ # Don't establish new connection if not connected: we apparently not in transaction
128
+ return false unless connection || ActiveRecord::Base.connection_pool.active_connection?
129
+
130
+ connection ||= default_connection
99
131
  # service transactions (tests and database_cleaner) are not joinable
100
132
  connection.transaction_open? && connection.current_transaction.joinable?
101
133
  end
134
+
135
+ private
136
+
137
+ def default_connection
138
+ ActiveRecord::Base.connection
139
+ end
102
140
  end
103
141
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: after_commit_everywhere
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Novikov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-05 00:00:00.000000000 Z
11
+ date: 2022-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -214,6 +214,7 @@ files:
214
214
  - gemfiles/activerecord_5_2.gemfile
215
215
  - gemfiles/activerecord_6_0.gemfile
216
216
  - gemfiles/activerecord_6_1.gemfile
217
+ - gemfiles/activerecord_7_0.gemfile
217
218
  - gemfiles/activerecord_master.gemfile
218
219
  - lib/after_commit_everywhere.rb
219
220
  - lib/after_commit_everywhere/version.rb