active_record_compose 0.8.0 → 0.9.0
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/CHANGELOG.md +7 -0
- data/README.md +2 -47
- data/lib/active_record_compose/delegate_attribute.rb +2 -2
- data/lib/active_record_compose/model.rb +16 -209
- data/lib/active_record_compose/version.rb +1 -1
- data/sig/_internal/package_private.rbs +1 -1
- data/sig/active_record_compose.rbs +3 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dba7d13bf8f2dc9ef449ead00c1a7ae3fff83e216f07b5d11606659a3c1f4650
|
4
|
+
data.tar.gz: 883a9480ff3e6bd4c99246c12200a7b5a6e44103c0d1c967ce97c4536aa478b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 905bf7969733f738e00726f0dc7ed1442bce1f598485a72a0478fd67069c556b5d8299fdc5485636b1194e095649df550ba9f3c01ffb42c107a8a69afcde85ae
|
7
|
+
data.tar.gz: 22f44a63d515d31682f22641e112c3bf720c5b3ff29c8fb0a30ceb777b23847a74f053eb3591211c35bfe2e2f96de345523236d08b30365059fc3a7421437bf4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.9.0] - 2025-03-16
|
4
|
+
|
5
|
+
- removed `persisted_flag_callback_control` support.
|
6
|
+
- Omitted `:private` option from `delegate_attribute` because, assuming the
|
7
|
+
behavior and use cases of `ActiveModel::Attributes.attribute`, making it private is unnecessary.
|
8
|
+
- Added the URL for the sample application to the README
|
9
|
+
|
3
10
|
## [0.8.0] - 2025-02-22
|
4
11
|
|
5
12
|
- changed `persisted_flag_callback_control` default from `false` to `true`.
|
data/README.md
CHANGED
@@ -286,18 +286,11 @@ end
|
|
286
286
|
|
287
287
|
### Callback ordering by `#persisted?`
|
288
288
|
|
289
|
-
The behavior of `(before|after|around)_create` and `(before|after|around)_update` hooks
|
290
|
-
the state of the `persisted_flag_callback_control` setting.
|
291
|
-
default value is `true`, behavior when set to `false` will be removed in the next release.
|
292
|
-
|
293
|
-
When `persisted_flag_callback_control` is set to `true`, it behaves almost like callback control in ActiveRecord.
|
294
|
-
Depending on the evaluation result of `#persisted?`,
|
289
|
+
The behavior of `(before|after|around)_create` and `(before|after|around)_update` hooks depending on the evaluation result of `#persisted?`,
|
295
290
|
either the create-related callbacks or the update-related callbacks will be triggered.
|
296
291
|
|
297
292
|
```ruby
|
298
293
|
class ComposedModel < ActiveRecordCompose::Model
|
299
|
-
self.persisted_flag_callback_control = true # In the future, true will be the default and false will no longer be supported.
|
300
|
-
|
301
294
|
# ...
|
302
295
|
|
303
296
|
before_save { puts 'before_save called!' }
|
@@ -345,48 +338,10 @@ model.save # or `model.update` (the same callbacks will be triggered in all case
|
|
345
338
|
# after_save called!
|
346
339
|
```
|
347
340
|
|
348
|
-
When `persisted_flag_callback_control` is set to false,
|
349
|
-
the execution of `#create`, `#update`, or `#save` determines which callbacks will be triggered.
|
350
|
-
This behavior will no longer be supported in the next release.
|
351
|
-
|
352
|
-
```ruby
|
353
|
-
class ComposedModel < ActiveRecordCompose::Model
|
354
|
-
self.persisted_flag_callback_control = false # Currently defaults to false, but will no longer be supported in the future.
|
355
|
-
|
356
|
-
# ...
|
357
|
-
|
358
|
-
before_save { puts 'before_save called!' }
|
359
|
-
before_create { puts 'before_create called!' }
|
360
|
-
before_update { puts 'before_update called!' }
|
361
|
-
after_save { puts 'after_save called!' }
|
362
|
-
after_create { puts 'after_create called!' }
|
363
|
-
after_update { puts 'after_update called!' }
|
364
|
-
end
|
365
|
-
```
|
366
|
-
|
367
|
-
```ruby
|
368
|
-
model = ComposedModel.new
|
369
|
-
|
370
|
-
model.save
|
371
|
-
# before_save called!
|
372
|
-
# after_save called!
|
373
|
-
|
374
|
-
model.create
|
375
|
-
# before_save called!
|
376
|
-
# before_create called!
|
377
|
-
# after_create called!
|
378
|
-
# after_save called!
|
379
|
-
|
380
|
-
model.update
|
381
|
-
# before_save called!
|
382
|
-
# before_update called!
|
383
|
-
# after_update called!
|
384
|
-
# after_save called!
|
385
|
-
```
|
386
|
-
|
387
341
|
## Links
|
388
342
|
|
389
343
|
- [Smart way to update multiple models simultaneously in Rails](https://dev.to/hamajyotan/smart-way-to-update-multiple-models-simultaneously-in-rails-51b6)
|
344
|
+
- [Sample application as an example](https://github.com/hamajyotan/active_record_compose-example)
|
390
345
|
|
391
346
|
## Development
|
392
347
|
|
@@ -45,7 +45,7 @@ module ActiveRecordCompose
|
|
45
45
|
module ClassMethods
|
46
46
|
# Defines the reader and writer for the specified attribute.
|
47
47
|
#
|
48
|
-
def delegate_attribute(*attributes, to:, allow_nil: nil
|
48
|
+
def delegate_attribute(*attributes, to:, allow_nil: nil)
|
49
49
|
delegates = attributes.flat_map do |attribute|
|
50
50
|
reader = attribute.to_s
|
51
51
|
writer = "#{attribute}="
|
@@ -53,7 +53,7 @@ module ActiveRecordCompose
|
|
53
53
|
[reader, writer]
|
54
54
|
end
|
55
55
|
|
56
|
-
delegate(*delegates, to:, allow_nil
|
56
|
+
delegate(*delegates, to:, allow_nil:)
|
57
57
|
self.delegated_attributes = delegated_attributes.to_a + attributes.map { _1.to_s }
|
58
58
|
end
|
59
59
|
end
|
@@ -15,46 +15,6 @@ module ActiveRecordCompose
|
|
15
15
|
include ActiveRecordCompose::DelegateAttribute
|
16
16
|
include ActiveRecordCompose::TransactionSupport
|
17
17
|
|
18
|
-
# This flag controls the callback sequence for models.
|
19
|
-
# The current default value is `true`, behavior when set to `false` will be removed in the next release.
|
20
|
-
#
|
21
|
-
# When `persisted_flag_callback_control` is set to `true`,
|
22
|
-
# the occurrence of callbacks depends on the evaluation result of `#persisted?`.
|
23
|
-
# Additionally, the definition of `#persisted?` itself can be appropriately overridden in subclasses.
|
24
|
-
#
|
25
|
-
# if `#persisted?` returns `false`:
|
26
|
-
# * before_save
|
27
|
-
# * before_create
|
28
|
-
# * after_create
|
29
|
-
# * after_save
|
30
|
-
#
|
31
|
-
# if `#persisted?` returns `true`:
|
32
|
-
# * before_save
|
33
|
-
# * before_update
|
34
|
-
# * after_update
|
35
|
-
# * after_save
|
36
|
-
#
|
37
|
-
# On the other hand, when `persisted_flag_callback_control` is set to `false`,
|
38
|
-
# the invoked methods during saving operations vary depending on the method used.
|
39
|
-
#
|
40
|
-
# when performing `#save` or `#save!`:
|
41
|
-
# * before_save
|
42
|
-
# * after_save
|
43
|
-
#
|
44
|
-
# when performing `#update` or `#update!`:
|
45
|
-
# * before_save
|
46
|
-
# * before_update
|
47
|
-
# * after_update
|
48
|
-
# * after_save
|
49
|
-
#
|
50
|
-
# when performing `#create` or `#create!`:
|
51
|
-
# * before_save
|
52
|
-
# * before_create
|
53
|
-
# * after_create
|
54
|
-
# * after_save
|
55
|
-
#
|
56
|
-
class_attribute :persisted_flag_callback_control, instance_accessor: false, default: true
|
57
|
-
|
58
18
|
define_model_callbacks :save
|
59
19
|
define_model_callbacks :create
|
60
20
|
define_model_callbacks :update
|
@@ -70,23 +30,16 @@ module ActiveRecordCompose
|
|
70
30
|
#
|
71
31
|
# The save is performed within a single transaction.
|
72
32
|
#
|
33
|
+
# Options like `:validate` and `:context` are not accepted as arguments.
|
34
|
+
# The need for such values indicates that operations from multiple contexts are being handled.
|
35
|
+
# However, if the contexts are different, it is recommended to separate them into different model definitions.
|
36
|
+
#
|
73
37
|
# @return [Boolean] returns true on success, false on failure.
|
74
38
|
def save
|
75
39
|
return false if invalid?
|
76
40
|
|
77
41
|
with_transaction_returning_status do
|
78
|
-
|
79
|
-
with_callbacks { save_models(bang: false) }
|
80
|
-
else
|
81
|
-
# steep:ignore:start
|
82
|
-
deprecator.warn(
|
83
|
-
'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
|
84
|
-
'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
|
85
|
-
'(Alternatively, exclude statements that set `false`)',
|
86
|
-
)
|
87
|
-
# steep:ignore:end
|
88
|
-
run_callbacks(:save) { save_models(bang: false) }
|
89
|
-
end
|
42
|
+
with_callbacks { save_models(bang: false) }
|
90
43
|
rescue ActiveRecord::RecordInvalid
|
91
44
|
false
|
92
45
|
end
|
@@ -97,165 +50,31 @@ module ActiveRecordCompose
|
|
97
50
|
#
|
98
51
|
# Saving, like `#save`, is performed within a single transaction.
|
99
52
|
#
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
with_transaction_returning_status do
|
104
|
-
if self.class.persisted_flag_callback_control
|
105
|
-
with_callbacks { save_models(bang: true) }
|
106
|
-
else
|
107
|
-
# steep:ignore:start
|
108
|
-
deprecator.warn(
|
109
|
-
'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
|
110
|
-
'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
|
111
|
-
'(Alternatively, exclude statements that set `false`)',
|
112
|
-
)
|
113
|
-
# steep:ignore:end
|
114
|
-
run_callbacks(:save) { save_models(bang: true) }
|
115
|
-
end
|
116
|
-
end || raise_on_save_error
|
117
|
-
end
|
118
|
-
|
119
|
-
# Behavior is same to `#save`, but `before_create` and `after_create` hooks fires.
|
120
|
-
#
|
121
|
-
# class ComposedModel < ActiveRecordCompose::Model
|
122
|
-
# # ...
|
123
|
-
#
|
124
|
-
# before_save { puts 'before_save called!' }
|
125
|
-
# before_create { puts 'before_create called!' }
|
126
|
-
# before_update { puts 'before_update called!' }
|
127
|
-
# after_save { puts 'after_save called!' }
|
128
|
-
# after_create { puts 'after_create called!' }
|
129
|
-
# after_update { puts 'after_update called!' }
|
130
|
-
# end
|
131
|
-
#
|
132
|
-
# model = ComposedModel.new
|
53
|
+
# Options like `:validate` and `:context` are not accepted as arguments.
|
54
|
+
# The need for such values indicates that operations from multiple contexts are being handled.
|
55
|
+
# However, if the contexts are different, it is recommended to separate them into different model definitions.
|
133
56
|
#
|
134
|
-
|
135
|
-
# # before_save called!
|
136
|
-
# # after_save called!
|
137
|
-
#
|
138
|
-
# model.create
|
139
|
-
# # before_save called!
|
140
|
-
# # before_create called!
|
141
|
-
# # after_create called!
|
142
|
-
# # after_save called!
|
143
|
-
#
|
144
|
-
# @deprecated
|
145
|
-
def create(attributes = {})
|
146
|
-
if self.class.persisted_flag_callback_control
|
147
|
-
raise '`#create` cannot be called. The context for creation or update is determined by the `#persisted` flag.'
|
148
|
-
end
|
149
|
-
|
150
|
-
# steep:ignore:start
|
151
|
-
deprecator.warn(
|
152
|
-
'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
|
153
|
-
'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
|
154
|
-
'(Alternatively, exclude statements that set `false`)',
|
155
|
-
)
|
156
|
-
# steep:ignore:end
|
157
|
-
|
158
|
-
assign_attributes(attributes)
|
159
|
-
return false if invalid?
|
160
|
-
|
161
|
-
with_transaction_returning_status do
|
162
|
-
with_callbacks(context: :create) { save_models(bang: false) }
|
163
|
-
rescue ActiveRecord::RecordInvalid
|
164
|
-
false
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
# Behavior is same to `#create`, but raises an exception prematurely on failure.
|
169
|
-
#
|
170
|
-
# @deprecated
|
171
|
-
def create!(attributes = {})
|
172
|
-
if self.class.persisted_flag_callback_control
|
173
|
-
raise '`#create` cannot be called. The context for creation or update is determined by the `#persisted` flag.'
|
174
|
-
end
|
175
|
-
|
176
|
-
# steep:ignore:start
|
177
|
-
deprecator.warn(
|
178
|
-
'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
|
179
|
-
'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
|
180
|
-
'(Alternatively, exclude statements that set `false`)',
|
181
|
-
)
|
182
|
-
# steep:ignore:end
|
183
|
-
|
184
|
-
assign_attributes(attributes)
|
57
|
+
def save!
|
185
58
|
valid? || raise_validation_error
|
186
59
|
|
187
60
|
with_transaction_returning_status do
|
188
|
-
with_callbacks
|
61
|
+
with_callbacks { save_models(bang: true) }
|
189
62
|
end || raise_on_save_error
|
190
63
|
end
|
191
64
|
|
192
|
-
#
|
193
|
-
#
|
194
|
-
# class ComposedModel < ActiveRecordCompose::Model
|
195
|
-
# # ...
|
196
|
-
#
|
197
|
-
# before_save { puts 'before_save called!' }
|
198
|
-
# before_create { puts 'before_create called!' }
|
199
|
-
# before_update { puts 'before_update called!' }
|
200
|
-
# after_save { puts 'after_save called!' }
|
201
|
-
# after_create { puts 'after_create called!' }
|
202
|
-
# after_update { puts 'after_update called!' }
|
203
|
-
# end
|
204
|
-
#
|
205
|
-
# model = ComposedModel.new
|
206
|
-
#
|
207
|
-
# model.save
|
208
|
-
# # before_save called!
|
209
|
-
# # after_save called!
|
210
|
-
#
|
211
|
-
# model.update
|
212
|
-
# # before_save called!
|
213
|
-
# # before_update called!
|
214
|
-
# # after_update called!
|
215
|
-
# # after_save called!
|
65
|
+
# Assign attributes and save.
|
216
66
|
#
|
67
|
+
# @return [Boolean] returns true on success, false on failure.
|
217
68
|
def update(attributes = {})
|
218
69
|
assign_attributes(attributes)
|
219
|
-
|
220
|
-
|
221
|
-
with_transaction_returning_status do
|
222
|
-
if self.class.persisted_flag_callback_control
|
223
|
-
with_callbacks { save_models(bang: false) }
|
224
|
-
else
|
225
|
-
# steep:ignore:start
|
226
|
-
deprecator.warn(
|
227
|
-
'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
|
228
|
-
'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
|
229
|
-
'(Alternatively, exclude statements that set `false`)',
|
230
|
-
)
|
231
|
-
# steep:ignore:end
|
232
|
-
with_callbacks(context: :update) { save_models(bang: false) }
|
233
|
-
end
|
234
|
-
rescue ActiveRecord::RecordInvalid
|
235
|
-
false
|
236
|
-
end
|
70
|
+
save
|
237
71
|
end
|
238
72
|
|
239
73
|
# Behavior is same to `#update`, but raises an exception prematurely on failure.
|
240
74
|
#
|
241
75
|
def update!(attributes = {})
|
242
76
|
assign_attributes(attributes)
|
243
|
-
|
244
|
-
|
245
|
-
with_transaction_returning_status do
|
246
|
-
if self.class.persisted_flag_callback_control
|
247
|
-
with_callbacks { save_models(bang: true) }
|
248
|
-
else
|
249
|
-
# steep:ignore:start
|
250
|
-
deprecator.warn(
|
251
|
-
'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
|
252
|
-
'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
|
253
|
-
'(Alternatively, exclude statements that set `false`)',
|
254
|
-
)
|
255
|
-
# steep:ignore:end
|
256
|
-
with_callbacks(context: :update) { save_models(bang: true) }
|
257
|
-
end
|
258
|
-
end || raise_on_save_error
|
77
|
+
save!
|
259
78
|
end
|
260
79
|
|
261
80
|
# Returns true if model is persisted.
|
@@ -275,13 +94,9 @@ module ActiveRecordCompose
|
|
275
94
|
models.__wrapped_models.lazy.select { _1.invalid? }.each { errors.merge!(_1) }
|
276
95
|
end
|
277
96
|
|
278
|
-
def with_callbacks(
|
279
|
-
run_callbacks(:save) { run_callbacks(callback_context(context:), &block) }
|
280
|
-
end
|
97
|
+
def with_callbacks(&block) = run_callbacks(:save) { run_callbacks(callback_context, &block) }
|
281
98
|
|
282
|
-
def callback_context
|
283
|
-
context || (persisted? ? :update : :create)
|
284
|
-
end
|
99
|
+
def callback_context = persisted? ? :update : :create
|
285
100
|
|
286
101
|
def save_models(bang:)
|
287
102
|
models.__wrapped_models.all? { bang ? _1.save! : _1.save }
|
@@ -292,13 +107,5 @@ module ActiveRecordCompose
|
|
292
107
|
def raise_on_save_error = raise ActiveRecord::RecordNotSaved.new(raise_on_save_error_message, self)
|
293
108
|
|
294
109
|
def raise_on_save_error_message = 'Failed to save the model.'
|
295
|
-
|
296
|
-
def deprecator
|
297
|
-
if ActiveRecord.respond_to?(:deprecator)
|
298
|
-
ActiveRecord.deprecator # steep:ignore
|
299
|
-
else # for rails 7.0.x or lower
|
300
|
-
ActiveSupport::Deprecation
|
301
|
-
end
|
302
|
-
end
|
303
110
|
end
|
304
111
|
end
|
@@ -24,7 +24,7 @@ module ActiveRecordCompose
|
|
24
24
|
def delegated_attributes: () -> Array[String]
|
25
25
|
|
26
26
|
module ClassMethods : Module
|
27
|
-
def delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: untyped
|
27
|
+
def delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: untyped?) -> untyped
|
28
28
|
def delegated_attributes: () -> Array[String]
|
29
29
|
def delegated_attributes=: (Array[String]) -> untyped
|
30
30
|
end
|
@@ -69,10 +69,7 @@ module ActiveRecordCompose
|
|
69
69
|
def self.after_commit: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
70
70
|
def self.after_rollback: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
71
71
|
|
72
|
-
def self.
|
73
|
-
def self.persisted_flag_callback_control=: (boolish) -> untyped
|
74
|
-
|
75
|
-
def self.delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: untyped?, ?private: untyped?) -> untyped
|
72
|
+
def self.delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: untyped?) -> untyped
|
76
73
|
def self.connection: -> ActiveRecord::ConnectionAdapters::AbstractAdapter
|
77
74
|
def self.lease_connection: -> ActiveRecord::ConnectionAdapters::AbstractAdapter
|
78
75
|
def self.with_connection: [T] () { () -> T } -> T
|
@@ -88,8 +85,8 @@ module ActiveRecordCompose
|
|
88
85
|
|
89
86
|
private
|
90
87
|
def models: -> ComposedCollection
|
91
|
-
def with_callbacks:
|
92
|
-
def callback_context:
|
88
|
+
def with_callbacks: { () -> bool } -> bool
|
89
|
+
def callback_context: -> (:create | :update)
|
93
90
|
def validate_models: -> void
|
94
91
|
def save_models: (bang: bool) -> bool
|
95
92
|
def raise_validation_error: -> bot
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_compose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hamajyotan
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-16 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activerecord
|
@@ -52,7 +52,7 @@ metadata:
|
|
52
52
|
homepage_uri: https://github.com/hamajyotan/active_record_compose
|
53
53
|
source_code_uri: https://github.com/hamajyotan/active_record_compose
|
54
54
|
changelog_uri: https://github.com/hamajyotan/active_record_compose/blob/main/CHANGELOG.md
|
55
|
-
documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.
|
55
|
+
documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.9.0
|
56
56
|
rubygems_mfa_required: 'true'
|
57
57
|
rdoc_options: []
|
58
58
|
require_paths:
|