after_commit_everywhere 1.0.0 → 1.2.1

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: b8b2847b6af9346bd5c042b364ccc1d94bbb696d82ef118362ad8085c2a96715
4
- data.tar.gz: b0089a18d4087f800e161477678a8dd69871d2413801e33556751a5e7d6731f4
3
+ metadata.gz: c67c4fd8f55095680c0519cef506d1b7296059b2dd4ce3c94c2a8787cc82c32e
4
+ data.tar.gz: e6feb83c65aa88072e56872105cf9511fccd9d4f5410afb9b9fc7060c768b79a
5
5
  SHA512:
6
- metadata.gz: 2c8342d72f9a2d076d62f52842aff823cdef8a8024e23f45c3360fdb662338878258efde0e2f09fe1f471d5830ed068d723af46f3ac628ef62daea843efdc723
7
- data.tar.gz: b6a74ddc5d7e8f34db311fd44d9b88627c2213c70931e6ebaf635f64cc74a3051724af088b4c2ba04f4420b856779626a1fbab2bc0f07c2c9c22168f5a9ff779
6
+ metadata.gz: f1679f32b243651bacc0d2966b4d72b67c1fe190f5a9165702ca11c9edd872b9bec0bd63fd0136b179a4255c5e98f9c957ce3fd67c7ce3454dbd1e201bcf0e01
7
+ data.tar.gz: c779815fd32f8e90f1ec01df87eab0a90a2425ad7e738d285d636b6e4762a0d7cb380f423a44087458dd2fdf533df57b8b78bc803ecb9858bf0eac70722cdb34
@@ -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,8 +44,5 @@ appraise "activerecord-master" do
38
44
  end
39
45
 
40
46
  gem "sqlite3", "~> 1.4"
41
- gem "rspec-rails", "~> 4.0"
42
-
43
- # See https://github.com/cgriego/active_attr/pull/183
44
- gem "active_attr", git: "https://github.com/Envek/active_attr.git", branch: "chore/loose-dependency-constraint"
47
+ gem "rspec-rails", "~> 5.0"
45
48
  end
data/CHANGELOG.md CHANGED
@@ -4,7 +4,53 @@ 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.1 (2022-06-10)
8
+
9
+ ### Fixed
10
+
11
+ - Connection leak from the connection pool when `after_commit` called outside Rails executor without connection checked out
12
+
13
+ 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.
14
+
15
+ 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.
16
+
17
+ 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.
18
+
19
+ See discussion at [issue #20](https://github.com/Envek/after_commit_everywhere/issues/20) for details.
20
+
21
+ [Pull request #21](https://github.com/Envek/after_commit_everywhere/pull/21) by [@Envek][].
22
+
23
+ ## 1.2.0 (2022-03-26)
24
+
25
+ ### Added
26
+
27
+ - Allow to change callbacks' behavior when they are called outside transaction:
28
+
29
+ ```ruby
30
+ AfterCommitEverywhere.after_commit(without_tx: :raise) do
31
+ # Will be executed only if was called within transaction
32
+ # Error will be raised otherwise
33
+ end
34
+ ```
35
+
36
+ Available values for `without_tx` keyword argument:
37
+ - `:execute` to execute callback immediately
38
+ - `:warn_and_execute` to print warning and execute immediately
39
+ - `:raise` to raise an exception instead of executing
40
+
41
+ [Pull request #18](https://github.com/Envek/after_commit_everywhere/pull/18) by [@lolripgg][].
42
+
43
+ ## 1.1.0 (2021-08-05)
44
+
45
+ ### Added
46
+
47
+ - Allow to call transactional callbacks directly on `AfterCommitEverywhere` module:
48
+
49
+ ```ruby
50
+ AfterCommitEverywhere.after_commit { puts "If you see me then transaction has been successfully commited!" }
51
+ ```
52
+
53
+ - Allow to call `in_transaction?` helper method from instance methods in classes that includes `AfterCommitEverywhere` module.
8
54
 
9
55
  ## 1.0.0 (2021-02-17)
10
56
 
@@ -42,3 +88,4 @@ See [#11](https://github.com/Envek/after_commit_everywhere/issues/11) for discus
42
88
  [@arjun810]: https://github.com/arjun810 "Arjun Singh"
43
89
  [@joevandyk]: https://github.com/joevandyk "Joe Van Dyk"
44
90
  [@stokarenko]: https://github.com/stokarenko "Sergey Tokarenko"
91
+ [@lolripgg]: https://github.com/lolripgg "James Brewer"
data/Gemfile.lock CHANGED
@@ -1,171 +1,188 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- after_commit_everywhere (0.1.5)
4
+ after_commit_everywhere (1.2.0)
5
5
  activerecord (>= 4.2)
6
+ activesupport
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- actioncable (6.1.2.1)
11
- actionpack (= 6.1.2.1)
12
- activesupport (= 6.1.2.1)
11
+ actioncable (7.0.3)
12
+ actionpack (= 7.0.3)
13
+ activesupport (= 7.0.3)
13
14
  nio4r (~> 2.0)
14
15
  websocket-driver (>= 0.6.1)
15
- actionmailbox (6.1.2.1)
16
- actionpack (= 6.1.2.1)
17
- activejob (= 6.1.2.1)
18
- activerecord (= 6.1.2.1)
19
- activestorage (= 6.1.2.1)
20
- activesupport (= 6.1.2.1)
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)
21
22
  mail (>= 2.7.1)
22
- actionmailer (6.1.2.1)
23
- actionpack (= 6.1.2.1)
24
- actionview (= 6.1.2.1)
25
- activejob (= 6.1.2.1)
26
- activesupport (= 6.1.2.1)
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)
27
31
  mail (~> 2.5, >= 2.5.4)
32
+ net-imap
33
+ net-pop
34
+ net-smtp
28
35
  rails-dom-testing (~> 2.0)
29
- actionpack (6.1.2.1)
30
- actionview (= 6.1.2.1)
31
- activesupport (= 6.1.2.1)
32
- 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)
33
40
  rack-test (>= 0.6.3)
34
41
  rails-dom-testing (~> 2.0)
35
42
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
- actiontext (6.1.2.1)
37
- actionpack (= 6.1.2.1)
38
- activerecord (= 6.1.2.1)
39
- activestorage (= 6.1.2.1)
40
- activesupport (= 6.1.2.1)
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)
41
49
  nokogiri (>= 1.8.5)
42
- actionview (6.1.2.1)
43
- activesupport (= 6.1.2.1)
50
+ actionview (7.0.3)
51
+ activesupport (= 7.0.3)
44
52
  builder (~> 3.1)
45
53
  erubi (~> 1.4)
46
54
  rails-dom-testing (~> 2.0)
47
55
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
- active_attr (0.15.1)
49
- actionpack (>= 3.0.2, < 6.2)
50
- activemodel (>= 3.0.2, < 6.2)
51
- activesupport (>= 3.0.2, < 6.2)
52
- activejob (6.1.2.1)
53
- activesupport (= 6.1.2.1)
56
+ activejob (7.0.3)
57
+ activesupport (= 7.0.3)
54
58
  globalid (>= 0.3.6)
55
- activemodel (6.1.2.1)
56
- activesupport (= 6.1.2.1)
57
- activerecord (6.1.2.1)
58
- activemodel (= 6.1.2.1)
59
- activesupport (= 6.1.2.1)
60
- activestorage (6.1.2.1)
61
- actionpack (= 6.1.2.1)
62
- activejob (= 6.1.2.1)
63
- activerecord (= 6.1.2.1)
64
- activesupport (= 6.1.2.1)
65
- marcel (~> 0.3.1)
66
- mimemagic (~> 0.3.2)
67
- activesupport (6.1.2.1)
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)
70
+ mini_mime (>= 1.1.0)
71
+ activesupport (7.0.3)
68
72
  concurrent-ruby (~> 1.0, >= 1.0.2)
69
73
  i18n (>= 1.6, < 2)
70
74
  minitest (>= 5.1)
71
75
  tzinfo (~> 2.0)
72
- zeitwerk (~> 2.3)
73
- anyway_config (2.1.0)
74
- ruby-next-core (>= 0.11.0)
75
- appraisal (2.3.0)
76
+ anyway_config (2.3.0)
77
+ ruby-next-core (>= 0.14.0)
78
+ appraisal (2.4.1)
76
79
  bundler
77
80
  rake
78
81
  thor (>= 0.14.0)
79
82
  ast (2.4.2)
80
83
  builder (3.2.4)
81
84
  coderay (1.1.3)
82
- concurrent-ruby (1.1.8)
85
+ concurrent-ruby (1.1.10)
83
86
  crass (1.0.6)
84
- diff-lcs (1.4.4)
87
+ diff-lcs (1.5.0)
88
+ digest (3.1.0)
89
+ dry-initializer (3.1.1)
85
90
  erubi (1.10.0)
86
- globalid (0.4.2)
87
- activesupport (>= 4.2.0)
88
- i18n (1.8.9)
91
+ globalid (1.0.0)
92
+ activesupport (>= 5.0)
93
+ i18n (1.10.0)
89
94
  concurrent-ruby (~> 1.0)
90
- isolator (0.7.0)
95
+ isolator (0.8.0)
91
96
  sniffer (>= 0.3.1)
92
97
  jaro_winkler (1.5.4)
93
- loofah (2.9.0)
98
+ loofah (2.18.0)
94
99
  crass (~> 1.0.2)
95
100
  nokogiri (>= 1.5.9)
96
101
  mail (2.7.1)
97
102
  mini_mime (>= 0.1.1)
98
- marcel (0.3.3)
99
- mimemagic (~> 0.3.2)
103
+ marcel (1.0.2)
100
104
  method_source (1.0.0)
101
- mimemagic (0.3.5)
102
- mini_mime (1.0.2)
103
- mini_portile2 (2.5.0)
104
- minitest (5.14.3)
105
- nio4r (2.5.5)
106
- nokogiri (1.11.1)
107
- mini_portile2 (~> 2.5.0)
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
122
+ nio4r (2.5.8)
123
+ nokogiri (1.13.6)
124
+ mini_portile2 (~> 2.8.0)
108
125
  racc (~> 1.4)
109
- parallel (1.20.1)
110
- parser (3.0.0.0)
126
+ parallel (1.22.1)
127
+ parser (3.1.2.0)
111
128
  ast (~> 2.4.1)
112
- pry (0.14.0)
129
+ pry (0.14.1)
113
130
  coderay (~> 1.1)
114
131
  method_source (~> 1.0)
115
- racc (1.5.2)
116
- rack (2.2.3)
132
+ racc (1.6.0)
133
+ rack (2.2.3.1)
117
134
  rack-test (1.1.0)
118
135
  rack (>= 1.0, < 3)
119
- rails (6.1.2.1)
120
- actioncable (= 6.1.2.1)
121
- actionmailbox (= 6.1.2.1)
122
- actionmailer (= 6.1.2.1)
123
- actionpack (= 6.1.2.1)
124
- actiontext (= 6.1.2.1)
125
- actionview (= 6.1.2.1)
126
- activejob (= 6.1.2.1)
127
- activemodel (= 6.1.2.1)
128
- activerecord (= 6.1.2.1)
129
- activestorage (= 6.1.2.1)
130
- activesupport (= 6.1.2.1)
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)
131
148
  bundler (>= 1.15.0)
132
- railties (= 6.1.2.1)
133
- sprockets-rails (>= 2.0.0)
149
+ railties (= 7.0.3)
134
150
  rails-dom-testing (2.0.3)
135
151
  activesupport (>= 4.2.0)
136
152
  nokogiri (>= 1.6)
137
- rails-html-sanitizer (1.3.0)
153
+ rails-html-sanitizer (1.4.3)
138
154
  loofah (~> 2.3)
139
- railties (6.1.2.1)
140
- actionpack (= 6.1.2.1)
141
- activesupport (= 6.1.2.1)
155
+ railties (7.0.3)
156
+ actionpack (= 7.0.3)
157
+ activesupport (= 7.0.3)
142
158
  method_source
143
- rake (>= 0.8.7)
159
+ rake (>= 12.2)
144
160
  thor (~> 1.0)
145
- rainbow (3.0.0)
146
- rake (13.0.3)
147
- rexml (3.2.4)
148
- rspec (3.10.0)
149
- rspec-core (~> 3.10.0)
150
- rspec-expectations (~> 3.10.0)
151
- rspec-mocks (~> 3.10.0)
152
- rspec-core (3.10.1)
153
- rspec-support (~> 3.10.0)
154
- rspec-expectations (3.10.1)
161
+ zeitwerk (~> 2.5)
162
+ rainbow (3.1.1)
163
+ rake (13.0.6)
164
+ rexml (3.2.5)
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)
155
172
  diff-lcs (>= 1.2.0, < 2.0)
156
- rspec-support (~> 3.10.0)
157
- rspec-mocks (3.10.2)
173
+ rspec-support (~> 3.11.0)
174
+ rspec-mocks (3.11.1)
158
175
  diff-lcs (>= 1.2.0, < 2.0)
159
- rspec-support (~> 3.10.0)
160
- rspec-rails (4.0.2)
161
- actionpack (>= 4.2)
162
- activesupport (>= 4.2)
163
- railties (>= 4.2)
176
+ rspec-support (~> 3.11.0)
177
+ rspec-rails (5.1.2)
178
+ actionpack (>= 5.2)
179
+ activesupport (>= 5.2)
180
+ railties (>= 5.2)
164
181
  rspec-core (~> 3.10)
165
182
  rspec-expectations (~> 3.10)
166
183
  rspec-mocks (~> 3.10)
167
184
  rspec-support (~> 3.10)
168
- rspec-support (3.10.2)
185
+ rspec-support (3.11.0)
169
186
  rubocop (0.81.0)
170
187
  jaro_winkler (~> 1.5.1)
171
188
  parallel (~> 1.10)
@@ -174,27 +191,22 @@ GEM
174
191
  rexml
175
192
  ruby-progressbar (~> 1.7)
176
193
  unicode-display_width (>= 1.4.0, < 2.0)
177
- ruby-next-core (0.12.0)
194
+ ruby-next-core (0.15.1)
178
195
  ruby-progressbar (1.11.0)
179
- sniffer (0.4.0)
180
- active_attr (>= 0.10.2)
196
+ sniffer (0.5.0)
181
197
  anyway_config (>= 1.0)
182
- sprockets (4.0.2)
183
- concurrent-ruby (~> 1.0)
184
- rack (> 1, < 3)
185
- sprockets-rails (3.2.2)
186
- actionpack (>= 4.0)
187
- activesupport (>= 4.0)
188
- sprockets (>= 3.0.0)
198
+ dry-initializer (~> 3)
189
199
  sqlite3 (1.4.2)
190
- thor (1.1.0)
200
+ strscan (3.0.3)
201
+ thor (1.2.1)
202
+ timeout (0.3.0)
191
203
  tzinfo (2.0.4)
192
204
  concurrent-ruby (~> 1.0)
193
- unicode-display_width (1.7.0)
194
- websocket-driver (0.7.3)
205
+ unicode-display_width (1.8.0)
206
+ websocket-driver (0.7.5)
195
207
  websocket-extensions (>= 0.1.0)
196
208
  websocket-extensions (0.1.5)
197
- zeitwerk (2.4.2)
209
+ zeitwerk (2.5.4)
198
210
 
199
211
  PLATFORMS
200
212
  ruby
@@ -213,4 +225,4 @@ DEPENDENCIES
213
225
  sqlite3 (~> 1.3, >= 1.3.6)
214
226
 
215
227
  BUNDLED WITH
216
- 2.2.9
228
+ 2.3.10
data/README.md CHANGED
@@ -55,6 +55,12 @@ ActiveRecord::Base.transaction do
55
55
  end
56
56
  ```
57
57
 
58
+ Or call it directly on module:
59
+
60
+ ```ruby
61
+ AfterCommitEverywhere.after_commit { puts "We're all done!" }
62
+ ```
63
+
58
64
  That's it!
59
65
 
60
66
  But the main benefit is that it works with nested `transaction` blocks (may be even spread across many files in your codebase):
@@ -107,6 +113,21 @@ If called outside transaction will raise an exception!
107
113
 
108
114
  Please keep in mind ActiveRecord's [limitations for rolling back nested transactions](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions).
109
115
 
116
+ ### Available helper methods
117
+
118
+ #### `in_transaction?`
119
+
120
+ Returns `true` when called inside open transaction, `false` otherwise.
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
+
110
131
  ### FAQ
111
132
 
112
133
  #### Does it works with transactional_test or DatabaseCleaner
@@ -133,6 +154,34 @@ By calling [the class level `after_commit` method on models](https://api.rubyonr
133
154
 
134
155
  See https://github.com/Envek/after_commit_everywhere/issues/13 for details.
135
156
 
157
+ #### But what if I want to use it inside models anyway?
158
+
159
+ In class-level methods call `AfterCommitEverywhere.after_commit` directly:
160
+
161
+ ```ruby
162
+ class Post < ActiveRecord::Base
163
+ def self.bulk_ops
164
+ find_each do
165
+ AfterCommitEverywhere.after_commit { puts "Now it works as expected!" }
166
+ end
167
+ end
168
+ end
169
+ ```
170
+
171
+ For usage in instance-level methods include this module to your model class (or right into your `ApplicationRecord`):
172
+
173
+ ```ruby
174
+ class Post < ActiveRecord::Base
175
+ include AfterCommitEverywhere
176
+
177
+ def do_some_stuff
178
+ after_commit { puts "Now it works!" }
179
+ end
180
+ end
181
+ ```
182
+
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).
184
+
136
185
  ## Development
137
186
 
138
187
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ["lib"]
30
30
 
31
31
  spec.add_dependency "activerecord", ">= 4.2"
32
+ spec.add_dependency "activesupport"
32
33
  spec.add_development_dependency "appraisal"
33
34
  spec.add_development_dependency "bundler", "~> 2.0"
34
35
  spec.add_development_dependency "isolator", "~> 0.7"
@@ -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,7 +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"
12
- gem "active_attr", git: "https://github.com/Envek/active_attr.git", branch: "chore/loose-dependency-constraint"
11
+ gem "rspec-rails", "~> 5.0"
13
12
 
14
13
  gemspec path: "../"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AfterCommitEverywhere
4
- VERSION = "1.0.0"
4
+ VERSION = "1.2.1"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record"
4
+ require "active_support/core_ext/module/delegation"
4
5
 
5
6
  require "after_commit_everywhere/version"
6
7
  require "after_commit_everywhere/wrap"
@@ -12,87 +13,129 @@ require "after_commit_everywhere/wrap"
12
13
  module AfterCommitEverywhere
13
14
  class NotInTransaction < RuntimeError; end
14
15
 
15
- # Runs +callback+ after successful commit of outermost transaction for
16
- # database +connection+.
17
- #
18
- # If called outside transaction it will execute callback immediately.
19
- #
20
- # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
21
- # @param callback [#call] Callback to be executed
22
- # @return void
23
- def after_commit(connection: ActiveRecord::Base.connection, &callback)
24
- AfterCommitEverywhere.register_callback(
25
- connection: connection,
26
- name: __method__,
27
- callback: callback,
28
- no_tx_action: :execute,
29
- )
30
- end
16
+ delegate :after_commit, :before_commit, :after_rollback, to: AfterCommitEverywhere
17
+ delegate :in_transaction?, to: AfterCommitEverywhere
31
18
 
32
- # Runs +callback+ before committing of outermost transaction for +connection+.
33
- #
34
- # If called outside transaction it will execute callback immediately.
35
- #
36
- # Available only since Ruby on Rails 5.0. See https://github.com/rails/rails/pull/18936
37
- #
38
- # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
39
- # @param callback [#call] Callback to be executed
40
- # @return void
41
- def before_commit(connection: ActiveRecord::Base.connection, &callback)
42
- if ActiveRecord::VERSION::MAJOR < 5
43
- raise NotImplementedError, "#{__method__} works only with Rails 5.0+"
44
- end
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
45
28
 
46
- AfterCommitEverywhere.register_callback(
47
- connection: connection,
48
- name: __method__,
49
- callback: callback,
50
- no_tx_action: :warn_and_execute,
29
+ class << self
30
+ # Runs +callback+ after successful commit of outermost transaction for
31
+ # database +connection+.
32
+ #
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}.
38
+ #
39
+ # @param callback [#call] Callback to be executed
40
+ # @return void
41
+ def after_commit(
42
+ connection: nil,
43
+ without_tx: EXECUTE,
44
+ &callback
51
45
  )
52
- end
46
+ register_callback(
47
+ connection: connection,
48
+ name: __method__,
49
+ callback: callback,
50
+ without_tx: without_tx,
51
+ )
52
+ end
53
53
 
54
- # Runs +callback+ after rolling back of transaction or savepoint (if declared
55
- # in nested transaction) for database +connection+.
56
- #
57
- # Caveat: do not raise +ActivRecord::Rollback+ in nested transaction block!
58
- # See http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions
59
- #
60
- # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
61
- # @param callback [#call] Callback to be executed
62
- # @return void
63
- # @raise [NotInTransaction] if called outside transaction.
64
- def after_rollback(connection: ActiveRecord::Base.connection, &callback)
65
- AfterCommitEverywhere.register_callback(
66
- connection: connection,
67
- name: __method__,
68
- callback: callback,
69
- no_tx_action: :exception,
54
+ # Runs +callback+ before committing of outermost transaction for +connection+.
55
+ #
56
+ # Available only since Ruby on Rails 5.0. See https://github.com/rails/rails/pull/18936
57
+ #
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
+ #
64
+ # @param callback [#call] Callback to be executed
65
+ # @return void
66
+ def before_commit(
67
+ connection: nil,
68
+ without_tx: WARN_AND_EXECUTE,
69
+ &callback
70
70
  )
71
- end
71
+ if ActiveRecord::VERSION::MAJOR < 5
72
+ raise NotImplementedError, "#{__method__} works only with Rails 5.0+"
73
+ end
72
74
 
73
- class << self
74
- def register_callback(connection:, name:, no_tx_action:, callback:)
75
+ register_callback(
76
+ connection: connection,
77
+ name: __method__,
78
+ callback: callback,
79
+ without_tx: without_tx,
80
+ )
81
+ end
82
+
83
+ # Runs +callback+ after rolling back of transaction or savepoint (if declared
84
+ # in nested transaction) for database +connection+.
85
+ #
86
+ # Caveat: do not raise +ActivRecord::Rollback+ in nested transaction block!
87
+ # See http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions
88
+ #
89
+ # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] Database connection to operate in. Defaults to +ActiveRecord::Base.connection+
90
+ # @param callback [#call] Callback to be executed
91
+ # @return void
92
+ # @raise [NotInTransaction] if called outside transaction.
93
+ def after_rollback(connection: nil, &callback)
94
+ register_callback(
95
+ connection: connection,
96
+ name: __method__,
97
+ callback: callback,
98
+ without_tx: RAISE,
99
+ )
100
+ end
101
+
102
+ # @api private
103
+ def register_callback(connection: nil, name:, without_tx:, callback:)
75
104
  raise ArgumentError, "Provide callback to #{name}" unless callback
76
105
 
77
106
  unless in_transaction?(connection)
78
- case no_tx_action
79
- when :warn_and_execute
107
+ case without_tx
108
+ when WARN_AND_EXECUTE
80
109
  warn "#{name}: No transaction open. Executing callback immediately."
81
110
  return callback.call
82
- when :execute
111
+ when EXECUTE
83
112
  return callback.call
84
- when :exception
113
+ when RAISE
85
114
  raise NotInTransaction, "#{name} is useless outside transaction"
115
+ else
116
+ raise ArgumentError, "Invalid \"without_tx\": \"#{without_tx}\""
86
117
  end
87
118
  end
119
+
120
+ connection ||= default_connection
88
121
  wrap = Wrap.new(connection: connection, "#{name}": callback)
89
122
  connection.add_transaction_record(wrap)
90
123
  end
91
124
 
92
125
  # Helper method to determine whether we're currently in transaction or not
93
- 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.connected?
129
+
130
+ connection ||= default_connection
94
131
  # service transactions (tests and database_cleaner) are not joinable
95
132
  connection.transaction_open? && connection.current_transaction.joinable?
96
133
  end
134
+
135
+ private
136
+
137
+ def default_connection
138
+ ActiveRecord::Base.connection
139
+ end
97
140
  end
98
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.0.0
4
+ version: 1.2.1
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-02-17 00:00:00.000000000 Z
11
+ date: 2022-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: appraisal
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -200,6 +214,7 @@ files:
200
214
  - gemfiles/activerecord_5_2.gemfile
201
215
  - gemfiles/activerecord_6_0.gemfile
202
216
  - gemfiles/activerecord_6_1.gemfile
217
+ - gemfiles/activerecord_7_0.gemfile
203
218
  - gemfiles/activerecord_master.gemfile
204
219
  - lib/after_commit_everywhere.rb
205
220
  - lib/after_commit_everywhere/version.rb
@@ -224,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
239
  - !ruby/object:Gem::Version
225
240
  version: '0'
226
241
  requirements: []
227
- rubygems_version: 3.1.4
242
+ rubygems_version: 3.1.6
228
243
  signing_key:
229
244
  specification_version: 4
230
245
  summary: Executes code after database commit wherever you want in your application