after_commit_everywhere 1.0.0 → 1.2.1

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: 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