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 +4 -4
- data/.github/workflows/test.yml +3 -9
- data/Appraisals +7 -4
- data/CHANGELOG.md +48 -1
- data/Gemfile.lock +134 -122
- data/README.md +49 -0
- data/after_commit_everywhere.gemspec +1 -0
- data/gemfiles/activerecord_7_0.gemfile +9 -0
- data/gemfiles/activerecord_master.gemfile +1 -2
- data/lib/after_commit_everywhere/version.rb +1 -1
- data/lib/after_commit_everywhere.rb +102 -59
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c67c4fd8f55095680c0519cef506d1b7296059b2dd4ce3c94c2a8787cc82c32e
|
4
|
+
data.tar.gz: e6feb83c65aa88072e56872105cf9511fccd9d4f5410afb9b9fc7060c768b79a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1679f32b243651bacc0d2966b4d72b67c1fe190f5a9165702ca11c9edd872b9bec0bd63fd0136b179a4255c5e98f9c957ce3fd67c7ce3454dbd1e201bcf0e01
|
7
|
+
data.tar.gz: c779815fd32f8e90f1ec01df87eab0a90a2425ad7e738d285d636b6e4762a0d7cb380f423a44087458dd2fdf533df57b8b78bc803ecb9858bf0eac70722cdb34
|
data/.github/workflows/test.yml
CHANGED
@@ -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", "~>
|
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
|
-
##
|
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 (
|
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 (
|
11
|
-
actionpack (=
|
12
|
-
activesupport (=
|
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 (
|
16
|
-
actionpack (=
|
17
|
-
activejob (=
|
18
|
-
activerecord (=
|
19
|
-
activestorage (=
|
20
|
-
activesupport (=
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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 (
|
30
|
-
actionview (=
|
31
|
-
activesupport (=
|
32
|
-
rack (~> 2.0, >= 2.0
|
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 (
|
37
|
-
actionpack (=
|
38
|
-
activerecord (=
|
39
|
-
activestorage (=
|
40
|
-
activesupport (=
|
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 (
|
43
|
-
activesupport (=
|
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
|
-
|
49
|
-
|
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 (
|
56
|
-
activesupport (=
|
57
|
-
activerecord (
|
58
|
-
activemodel (=
|
59
|
-
activesupport (=
|
60
|
-
activestorage (
|
61
|
-
actionpack (=
|
62
|
-
activejob (=
|
63
|
-
activerecord (=
|
64
|
-
activesupport (=
|
65
|
-
marcel (~> 0
|
66
|
-
|
67
|
-
activesupport (
|
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
|
-
|
73
|
-
|
74
|
-
|
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.
|
85
|
+
concurrent-ruby (1.1.10)
|
83
86
|
crass (1.0.6)
|
84
|
-
diff-lcs (1.
|
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.
|
87
|
-
activesupport (>=
|
88
|
-
i18n (1.
|
91
|
+
globalid (1.0.0)
|
92
|
+
activesupport (>= 5.0)
|
93
|
+
i18n (1.10.0)
|
89
94
|
concurrent-ruby (~> 1.0)
|
90
|
-
isolator (0.
|
95
|
+
isolator (0.8.0)
|
91
96
|
sniffer (>= 0.3.1)
|
92
97
|
jaro_winkler (1.5.4)
|
93
|
-
loofah (2.
|
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.
|
99
|
-
mimemagic (~> 0.3.2)
|
103
|
+
marcel (1.0.2)
|
100
104
|
method_source (1.0.0)
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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.
|
110
|
-
parser (3.
|
126
|
+
parallel (1.22.1)
|
127
|
+
parser (3.1.2.0)
|
111
128
|
ast (~> 2.4.1)
|
112
|
-
pry (0.14.
|
129
|
+
pry (0.14.1)
|
113
130
|
coderay (~> 1.1)
|
114
131
|
method_source (~> 1.0)
|
115
|
-
racc (1.
|
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 (
|
120
|
-
actioncable (=
|
121
|
-
actionmailbox (=
|
122
|
-
actionmailer (=
|
123
|
-
actionpack (=
|
124
|
-
actiontext (=
|
125
|
-
actionview (=
|
126
|
-
activejob (=
|
127
|
-
activemodel (=
|
128
|
-
activerecord (=
|
129
|
-
activestorage (=
|
130
|
-
activesupport (=
|
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 (=
|
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
|
153
|
+
rails-html-sanitizer (1.4.3)
|
138
154
|
loofah (~> 2.3)
|
139
|
-
railties (
|
140
|
-
actionpack (=
|
141
|
-
activesupport (=
|
155
|
+
railties (7.0.3)
|
156
|
+
actionpack (= 7.0.3)
|
157
|
+
activesupport (= 7.0.3)
|
142
158
|
method_source
|
143
|
-
rake (>=
|
159
|
+
rake (>= 12.2)
|
144
160
|
thor (~> 1.0)
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
rspec-
|
151
|
-
rspec-
|
152
|
-
|
153
|
-
|
154
|
-
|
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.
|
157
|
-
rspec-mocks (3.
|
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.
|
160
|
-
rspec-rails (
|
161
|
-
actionpack (>=
|
162
|
-
activesupport (>=
|
163
|
-
railties (>=
|
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.
|
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.
|
194
|
+
ruby-next-core (0.15.1)
|
178
195
|
ruby-progressbar (1.11.0)
|
179
|
-
sniffer (0.
|
180
|
-
active_attr (>= 0.10.2)
|
196
|
+
sniffer (0.5.0)
|
181
197
|
anyway_config (>= 1.0)
|
182
|
-
|
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
|
-
|
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.
|
194
|
-
websocket-driver (0.7.
|
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
|
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.
|
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"
|
@@ -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", "~>
|
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,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
|
-
|
16
|
-
|
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
|
-
#
|
33
|
-
#
|
34
|
-
|
35
|
-
#
|
36
|
-
#
|
37
|
-
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
46
|
+
register_callback(
|
47
|
+
connection: connection,
|
48
|
+
name: __method__,
|
49
|
+
callback: callback,
|
50
|
+
without_tx: without_tx,
|
51
|
+
)
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
71
|
+
if ActiveRecord::VERSION::MAJOR < 5
|
72
|
+
raise NotImplementedError, "#{__method__} works only with Rails 5.0+"
|
73
|
+
end
|
72
74
|
|
73
|
-
|
74
|
-
|
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
|
79
|
-
when
|
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
|
111
|
+
when EXECUTE
|
83
112
|
return callback.call
|
84
|
-
when
|
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 =
|
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.
|
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:
|
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.
|
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
|