active_record_compose 0.8.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b1f795843fd29ef6dcd9cf17e897938ea97fc8f32db35f0b444b36455e619a3
4
- data.tar.gz: 584e44a2c49c6861ad232f0c52c75b6d73abb550f39165fabe14690a71575c81
3
+ metadata.gz: dba7d13bf8f2dc9ef449ead00c1a7ae3fff83e216f07b5d11606659a3c1f4650
4
+ data.tar.gz: 883a9480ff3e6bd4c99246c12200a7b5a6e44103c0d1c967ce97c4536aa478b1
5
5
  SHA512:
6
- metadata.gz: 04bc96e1479134c02ad09ae5d014ad5ad93c6d6ae6914a39724d42152f691120ccfaa76c681e3790bb1b436b49cc39d57eb8bfe7f6fc73d064818e22738ce1c9
7
- data.tar.gz: e757a94164248e188c46413a706ec2418eb99c97f28bc5631305620c064b8fd7b04a6621d4809e405f95ac4d2228c22509700169f0049b581a1998ceba364acd
6
+ metadata.gz: 905bf7969733f738e00726f0dc7ed1442bce1f598485a72a0478fd67069c556b5d8299fdc5485636b1194e095649df550ba9f3c01ffb42c107a8a69afcde85ae
7
+ data.tar.gz: 22f44a63d515d31682f22641e112c3bf720c5b3ff29c8fb0a30ceb777b23847a74f053eb3591211c35bfe2e2f96de345523236d08b30365059fc3a7421437bf4
data/CHANGELOG.md CHANGED
@@ -1,9 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.8.1] - 2025-06-21
3
+ ## [0.9.0] - 2025-03-16
4
4
 
5
- - Add migration guide message.
6
- - Add upper version.
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
7
9
 
8
10
  ## [0.8.0] - 2025-02-22
9
11
 
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 depends on
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, private: 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:, private:)
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,24 +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
- if self.class.persisted_flag_callback_control
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
- 'cf. https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md ',
87
- )
88
- # steep:ignore:end
89
- run_callbacks(:save) { save_models(bang: false) }
90
- end
42
+ with_callbacks { save_models(bang: false) }
91
43
  rescue ActiveRecord::RecordInvalid
92
44
  false
93
45
  end
@@ -98,170 +50,31 @@ module ActiveRecordCompose
98
50
  #
99
51
  # Saving, like `#save`, is performed within a single transaction.
100
52
  #
101
- def save!
102
- valid? || raise_validation_error
103
-
104
- with_transaction_returning_status do
105
- if self.class.persisted_flag_callback_control
106
- with_callbacks { save_models(bang: true) }
107
- else
108
- # steep:ignore:start
109
- deprecator.warn(
110
- 'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
111
- 'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
112
- '(Alternatively, exclude statements that set `false`) ' \
113
- 'cf. https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md ',
114
- )
115
- # steep:ignore:end
116
- run_callbacks(:save) { save_models(bang: true) }
117
- end
118
- end || raise_on_save_error
119
- end
120
-
121
- # Behavior is same to `#save`, but `before_create` and `after_create` hooks fires.
122
- #
123
- # class ComposedModel < ActiveRecordCompose::Model
124
- # # ...
125
- #
126
- # before_save { puts 'before_save called!' }
127
- # before_create { puts 'before_create called!' }
128
- # before_update { puts 'before_update called!' }
129
- # after_save { puts 'after_save called!' }
130
- # after_create { puts 'after_create called!' }
131
- # after_update { puts 'after_update called!' }
132
- # end
133
- #
134
- # 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.
135
56
  #
136
- # model.save
137
- # # before_save called!
138
- # # after_save called!
139
- #
140
- # model.create
141
- # # before_save called!
142
- # # before_create called!
143
- # # after_create called!
144
- # # after_save called!
145
- #
146
- # @deprecated
147
- def create(attributes = {})
148
- if self.class.persisted_flag_callback_control
149
- raise '`#create` cannot be called. The context for creation or update is determined by the `#persisted` flag.'
150
- end
151
-
152
- # steep:ignore:start
153
- deprecator.warn(
154
- 'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
155
- 'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
156
- '(Alternatively, exclude statements that set `false`) ' \
157
- 'cf. https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md ',
158
- )
159
- # steep:ignore:end
160
-
161
- assign_attributes(attributes)
162
- return false if invalid?
163
-
164
- with_transaction_returning_status do
165
- with_callbacks(context: :create) { save_models(bang: false) }
166
- rescue ActiveRecord::RecordInvalid
167
- false
168
- end
169
- end
170
-
171
- # Behavior is same to `#create`, but raises an exception prematurely on failure.
172
- #
173
- # @deprecated
174
- def create!(attributes = {})
175
- if self.class.persisted_flag_callback_control
176
- raise '`#create` cannot be called. The context for creation or update is determined by the `#persisted` flag.'
177
- end
178
-
179
- # steep:ignore:start
180
- deprecator.warn(
181
- 'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
182
- 'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
183
- '(Alternatively, exclude statements that set `false`) ' \
184
- 'cf. https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md ',
185
- )
186
- # steep:ignore:end
187
-
188
- assign_attributes(attributes)
57
+ def save!
189
58
  valid? || raise_validation_error
190
59
 
191
60
  with_transaction_returning_status do
192
- with_callbacks(context: :create) { save_models(bang: true) }
61
+ with_callbacks { save_models(bang: true) }
193
62
  end || raise_on_save_error
194
63
  end
195
64
 
196
- # Behavior is same to `#save`, but `before_update` and `after_update` hooks fires.
197
- #
198
- # class ComposedModel < ActiveRecordCompose::Model
199
- # # ...
200
- #
201
- # before_save { puts 'before_save called!' }
202
- # before_create { puts 'before_create called!' }
203
- # before_update { puts 'before_update called!' }
204
- # after_save { puts 'after_save called!' }
205
- # after_create { puts 'after_create called!' }
206
- # after_update { puts 'after_update called!' }
207
- # end
208
- #
209
- # model = ComposedModel.new
210
- #
211
- # model.save
212
- # # before_save called!
213
- # # after_save called!
214
- #
215
- # model.update
216
- # # before_save called!
217
- # # before_update called!
218
- # # after_update called!
219
- # # after_save called!
65
+ # Assign attributes and save.
220
66
  #
67
+ # @return [Boolean] returns true on success, false on failure.
221
68
  def update(attributes = {})
222
69
  assign_attributes(attributes)
223
- return false if invalid?
224
-
225
- with_transaction_returning_status do
226
- if self.class.persisted_flag_callback_control
227
- with_callbacks { save_models(bang: false) }
228
- else
229
- # steep:ignore:start
230
- deprecator.warn(
231
- 'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
232
- 'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
233
- '(Alternatively, exclude statements that set `false`) ' \
234
- 'cf. https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md ',
235
- )
236
- # steep:ignore:end
237
- with_callbacks(context: :update) { save_models(bang: false) }
238
- end
239
- rescue ActiveRecord::RecordInvalid
240
- false
241
- end
70
+ save
242
71
  end
243
72
 
244
73
  # Behavior is same to `#update`, but raises an exception prematurely on failure.
245
74
  #
246
75
  def update!(attributes = {})
247
76
  assign_attributes(attributes)
248
- valid? || raise_validation_error
249
-
250
- with_transaction_returning_status do
251
- if self.class.persisted_flag_callback_control
252
- with_callbacks { save_models(bang: true) }
253
- else
254
- # steep:ignore:start
255
- deprecator.warn(
256
- 'The behavior with `persisted_flag_callback_control` set to `false` will be removed in 0.9.0. ' \
257
- 'Use `self.persisted_flag_callback_control = true` set to `true`. ' \
258
- '(Alternatively, exclude statements that set `false`) ' \
259
- 'cf. https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md ',
260
- )
261
- # steep:ignore:end
262
- with_callbacks(context: :update) { save_models(bang: true) }
263
- end
264
- end || raise_on_save_error
77
+ save!
265
78
  end
266
79
 
267
80
  # Returns true if model is persisted.
@@ -281,13 +94,9 @@ module ActiveRecordCompose
281
94
  models.__wrapped_models.lazy.select { _1.invalid? }.each { errors.merge!(_1) }
282
95
  end
283
96
 
284
- def with_callbacks(context: nil, &block)
285
- run_callbacks(:save) { run_callbacks(callback_context(context:), &block) }
286
- end
97
+ def with_callbacks(&block) = run_callbacks(:save) { run_callbacks(callback_context, &block) }
287
98
 
288
- def callback_context(context: nil)
289
- context || (persisted? ? :update : :create)
290
- end
99
+ def callback_context = persisted? ? :update : :create
291
100
 
292
101
  def save_models(bang:)
293
102
  models.__wrapped_models.all? { bang ? _1.save! : _1.save }
@@ -298,15 +107,5 @@ module ActiveRecordCompose
298
107
  def raise_on_save_error = raise ActiveRecord::RecordNotSaved.new(raise_on_save_error_message, self)
299
108
 
300
109
  def raise_on_save_error_message = 'Failed to save the model.'
301
-
302
- # steep:ignore:start
303
- def deprecator
304
- if ActiveRecord.respond_to?(:deprecator)
305
- ActiveRecord.deprecator
306
- else # for rails 7.0.x or lower
307
- ActiveSupport::Deprecation
308
- end
309
- end
310
- # steep:ignore:end
311
110
  end
312
111
  end
@@ -18,7 +18,7 @@ module ActiveRecordCompose
18
18
 
19
19
  def with_connection(&) = ar_class.with_connection(&) # steep:ignore
20
20
 
21
- def composite_primary_key? = false # steep:ignore
21
+ def composite_primary_key? = false
22
22
 
23
23
  private
24
24
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordCompose
4
- VERSION = '0.8.1'
4
+ VERSION = '0.9.0'
5
5
  end
@@ -7,15 +7,3 @@ require_relative 'active_record_compose/model'
7
7
 
8
8
  module ActiveRecordCompose
9
9
  end
10
-
11
- if ActiveRecordCompose::VERSION == '0.8.1'
12
- unless ENV['ACTIVE_RECORD_COMPOSE_SILENCE_DEPRECATION'] # rubocop:disable Style/SoleNestedConditional
13
- warn <<~WARN
14
-
15
- [DEPRECATION] You are using active_record_compose version 0.8.1, which is deprecated.
16
- Please upgrade to the latest version.
17
- See: https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md
18
-
19
- WARN
20
- end
21
- 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?, ?private: untyped?) -> 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.persisted_flag_callback_control: () -> boolish
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: (?context: (nil | :create | :update)) { () -> bool } -> bool
92
- def callback_context: (?context: (nil | :create | :update)) -> (:create | :update)
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.8.1
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-06-21 00:00:00.000000000 Z
10
+ date: 2025-03-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord
@@ -16,9 +16,6 @@ dependencies:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '7.0'
19
- - - "<"
20
- - !ruby/object:Gem::Version
21
- version: '8.1'
22
19
  type: :runtime
23
20
  prerelease: false
24
21
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,9 +23,6 @@ dependencies:
26
23
  - - ">="
27
24
  - !ruby/object:Gem::Version
28
25
  version: '7.0'
29
- - - "<"
30
- - !ruby/object:Gem::Version
31
- version: '8.1'
32
26
  description: activemodel form object pattern. it embraces multiple AR models and provides
33
27
  a transparent interface as if they were a single model.
34
28
  email:
@@ -42,7 +36,6 @@ files:
42
36
  - CODE_OF_CONDUCT.md
43
37
  - LICENSE.txt
44
38
  - README.md
45
- - UPGRADE.md
46
39
  - lib/active_record_compose.rb
47
40
  - lib/active_record_compose/composed_collection.rb
48
41
  - lib/active_record_compose/delegate_attribute.rb
@@ -59,17 +52,8 @@ metadata:
59
52
  homepage_uri: https://github.com/hamajyotan/active_record_compose
60
53
  source_code_uri: https://github.com/hamajyotan/active_record_compose
61
54
  changelog_uri: https://github.com/hamajyotan/active_record_compose/blob/main/CHANGELOG.md
62
- documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.8.1
55
+ documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.9.0
63
56
  rubygems_mfa_required: 'true'
64
- post_install_message: |2+
65
-
66
- Notice: This version (0.8.1) is deprecated.
67
-
68
- Please upgrade to the latest version of `active_record_compose` as soon as possible.
69
- Future releases will not support this version.
70
-
71
- See https://github.com/hamajyotan/active_record_compose/blob/v0.8.1/UPGRADE.md for migration steps.
72
-
73
57
  rdoc_options: []
74
58
  require_paths:
75
59
  - lib
@@ -88,4 +72,3 @@ rubygems_version: 3.6.2
88
72
  specification_version: 4
89
73
  summary: activemodel form object pattern
90
74
  test_files: []
91
- ...
data/UPGRADE.md DELETED
@@ -1,113 +0,0 @@
1
- # Migration Guide: `active_record_compose` 0.8.x to 0.9.0+
2
-
3
- ⚠️ **Breaking Change**
4
-
5
- This guide explains how to migrate from version **0.8.x** to **0.9.0 or later**, assuming that your codebase includes:
6
-
7
- ```ruby
8
- self.persisted_flag_callback_control = false
9
- ```
10
-
11
- This setting was officially **deprecated** in 0.9.0 and is **no longer supported**. Migration is required to adopt the current default behavior.
12
-
13
- ## Background
14
-
15
- In version **0.7.x**, the default value of `persisted_flag_callback_control` was `false`.
16
-
17
- In **0.8.x**, the default was changed to `true`.
18
- If you are still using `false` in your models, it means you have **explicitly overridden the default**, likely to preserve backward-compatible behavior.
19
-
20
- This guide helps you safely migrate to the new behavior while preserving intended callback semantics.
21
-
22
- ## Goal of the Migration
23
-
24
- - Remove any use of `persisted_flag_callback_control = false`
25
- - Adjust callback definitions to align with the semantics of `#persisted?`
26
-
27
- ## Step 1 – Remove Deprecated Flag
28
-
29
- Find and remove all instances of:
30
-
31
- ```diff
32
- -self.persisted_flag_callback_control = false
33
- ```
34
-
35
- ## Step 2 – Understand Callback Behavior Changes
36
-
37
- With `persisted_flag_callback_control = true`, whether a callback is fired depends on the return value of `#persisted?`, not the method used (`create` or `update`).
38
-
39
- ### When saving with `#update`:
40
-
41
- If `persisted?` returns `false`, then:
42
-
43
- - `before_update`
44
- - `after_update`
45
- - `around_update`
46
-
47
- will **not** be triggered.
48
-
49
- ✅ Recommended fix:
50
-
51
- If you don’t differentiate between creation and update phases, switch to `*_save` callbacks:
52
-
53
- ```diff
54
- - before_update :track_change
55
- + before_save :track_change
56
- ```
57
-
58
- ### When saving with `#create`:
59
-
60
- If `persisted?` returns `true`, then:
61
-
62
- - `before_create`
63
- - `after_create`
64
- - `around_create`
65
-
66
- will **not** be triggered.
67
-
68
- ✅ Recommended fix:
69
-
70
- Again, prefer `*_save` if you're using shared logic across creation and update:
71
-
72
- ```diff
73
- - after_create :send_notification
74
- + after_save :send_notification
75
- ```
76
-
77
- ## Step 3 – Override `#persisted?` if Needed
78
-
79
- If your composed model wraps an ActiveRecord instance and delegates its persistence logic, be sure to override `#persisted?` to reflect the correct state:
80
-
81
- ```ruby
82
- class Foo < ActiveRecordCompose::Model
83
- def initialize(bar = Bar.new)
84
- super()
85
- @bar = bar
86
- end
87
-
88
- def persisted? = bar.persisted?
89
-
90
- private
91
-
92
- attr_reader :bar
93
- end
94
- ```
95
-
96
- ## Migration Checklist ✅
97
-
98
- - [ ] All models now `persisted_flag_callback_control` omit it entirely
99
- - [ ] All callback definitions have been reviewed and updated
100
- - [ ] Any `*_create` or `*_update` callbacks have been replaced with `*_save` where applicable
101
- - [ ] `#persisted?` is correctly overridden where needed
102
- - [ ] All tests pass and expected callbacks are fired
103
-
104
- ## Why This Change?
105
-
106
- By aligning callback behavior with `persisted?`, you gain:
107
-
108
- - Clearer intent and semantics
109
- - More accurate behavior when composing or wrapping persisted models
110
- - Improved compatibility with Rails conventions
111
- - Less surprising callback triggering
112
-
113
- If you have questions or run into edge cases, feel free to [open an issue](https://github.com/hamajyotan/active_record_compose/issues) or start a discussion.