active_record_compose 0.12.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 954ce34124a1c8e83a45710e104dd965c407afb5ba296b74d4a4e5f9d13d971a
4
- data.tar.gz: c1bb35ef5458a804f243b886c037aff3794822477ea2aaf5a57bfb12a4001477
3
+ metadata.gz: a8fa5fa4117b180d20233c6dc06ca8797c2c9931cca2708e5a01bd2b560c42d2
4
+ data.tar.gz: cdb73d45e04a3195f9834390f9e9b6e8242e4a9b325a6ec684d3c7c2f97076ef
5
5
  SHA512:
6
- metadata.gz: 2e7f81f304cec10420cb4f405ad8ad7f93f3811c7f43bf9952c05dbca84e651bbf0c851e648349d7e93986cf67cb177110785588a47c8951718f4d271cf53944
7
- data.tar.gz: 8ac490bd69c0d51e6e89f1f198a4e052eccbeedcf1b234edfa8c9635819fe336bbe10b6b64b6b55907524543ad34eb9343892b00f54f2737a65c45c120456afa
6
+ metadata.gz: 2317d9e39b054c728b0847c6cde3f556edfcfa57de9b1c6023f10cf264f5c498bcf654e252d7a29c0a071d349ade5f00943e512938a427b6d253bd43592ebace
7
+ data.tar.gz: 71ad4690a7af527a1d323e3ccc84b25c0b7f875fcc3655883d0b8c2e35fe165b3b1f17a6201152e6d0281b21716976c77eec26db6c5712c0630d2741e6b72886
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.1] - 2025-10-17
4
+
5
+ * Removed the private interface `composite_primary_key?`
6
+ This was previously an internal ActiveRecord dependency, but was not exposed in the release version.
7
+ (https://github.com/hamajyotan/active_record_compose/pull/39)
8
+ * Relaxed ActiveRecord dependency upper bound to < 8.2
9
+ (https://github.com/hamajyotan/active_record_compose/pull/42)
10
+
11
+ ## [1.0.0] - 2025-09-23
12
+
13
+ - drop support rails 7.0.x
14
+
3
15
  ## [0.12.0] - 2025-08-21
4
16
 
5
17
  - Omits default arguments for `#update` and `#update!`. It's to align I/F with ActiveRecord.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # ActiveRecordCompose
2
2
 
3
- activemodel (activerecord) form object pattern. it embraces multiple AR models and provides a transparent interface as if they were a single model.
3
+ ActiveRecordCompose lets you build form objects that combine multiple ActiveRecord models into a single, unified interface.
4
+ More than just a simple form object, it is designed as a **business-oriented composed model** that encapsulates complex operations-such as user registration spanning multiple tables-making them easier to write, validate, and maintain.
4
5
 
5
6
  [![Gem Version](https://badge.fury.io/rb/active_record_compose.svg)](https://badge.fury.io/rb/active_record_compose)
6
7
  ![CI](https://github.com/hamajyotan/active_record_compose/workflows/CI/badge.svg)
@@ -10,16 +11,16 @@ activemodel (activerecord) form object pattern. it embraces multiple AR models a
10
11
 
11
12
  - [Motivation](#motivation)
12
13
  - [Installation](#installation)
13
- - [Usage](#usage)
14
- - [Basic usage](#basic-usage)
15
- - [`delegate_attribute`](#delegate_attribute)
16
- - [Promotion to model from AR-model errors](#promotion-to-model-from-ar-model-errors)
17
- - [I18n](#i18n)
14
+ - [Quick Start](#quick-start)
15
+ - [Basic Example](#basic-example)
16
+ - [Attribute Delegation](#attribute-delegation)
17
+ - [Unified Error Handling](#unified-error-handling)
18
+ - [I18n Support](#i18n-support)
18
19
  - [Advanced Usage](#advanced-usage)
19
- - [`destroy` option](#destroy-option)
20
- - [Callback ordering by `#persisted?`](#callback-ordering-by-persisted)
21
- - [`#save` with custom context option](#save-with-custom-context-option)
22
- - [Sample application as an example](#sample-application-as-an-example)
20
+ - [Destroy Option](#destroy-option)
21
+ - [Callback ordering with `#persisted?`](#callback-ordering-with-persisted)
22
+ - [Notes on adding models dynamically](#notes-on-adding-models-dynamically)
23
+ - [Sample Application](#sample-application)
23
24
  - [Links](#links)
24
25
  - [Development](#development)
25
26
  - [Contributing](#contributing)
@@ -28,11 +29,20 @@ activemodel (activerecord) form object pattern. it embraces multiple AR models a
28
29
 
29
30
  ## Motivation
30
31
 
31
- `ActiveRecord::Base` is responsible for persisting data to the database, and by defining validations and callbacks, it allows you to structure your use cases effectively. This is a crucial component of Rails. However, when a specific model starts being updated by multiple different use cases, validations and callbacks may require conditions such as `on: :context` or `save(validate: false)`. As a result, the model needs to account for multiple dependent use cases, leading to increased complexity.
32
+ In Rails, `ActiveRecord::Base` is responsible for persisting data to the database.
33
+ By defining validations and callbacks, you can model use cases effectively.
32
34
 
33
- In such cases, `ActiveModel::Model` becomes useful. It provides the same interfaces as `ActiveRecord::Base`, such as `attribute` and `errors`, allowing it to be used similarly to an ActiveRecord model. Additionally, it enables you to define validations and callbacks within a limited context, preventing conditions related to multiple contexts from being embedded in `ActiveRecord::Base` validations and callbacks. This results in simpler, more maintainable code.
35
+ However, when a single model must serve multiple different use cases, you often end up with conditional validations (`on: :context`) or workarounds like `save(validate: false)`.
36
+ This mixes unrelated concerns into one model, leading to unnecessary complexity.
34
37
 
35
- This gem is built on `ActiveModel::Model` and acts as a first-class model within the Rails context. It provides methods for performing batch and safe updates on 0..N encapsulated models, enables transparent attribute access, and facilitates access to error information.
38
+ `ActiveModel::Model` helps here it provides the familiar API (`attribute`, `errors`, validations, callbacks) without persistence, so you can isolate logic per use case.
39
+
40
+ **ActiveRecordCompose** builds on `ActiveModel::Model` and is a powerful **business object** that acts as a first-class model within Rails.
41
+ - Transparently accesses attributes across multiple models
42
+ - Saves all associated models atomically in a transaction
43
+ - Collects and exposes error information consistently
44
+
45
+ This leads to cleaner domain models, better separation of concerns, and fewer surprises in validations and callbacks.
36
46
 
37
47
  ## Installation
38
48
 
@@ -48,15 +58,15 @@ Then bundle
48
58
  $ bundle
49
59
  ```
50
60
 
51
- ## Usage
61
+ ## Quick Start
52
62
 
53
- ### Basic usage
63
+ ### Basic Example
54
64
 
55
- (Below, it is assumed that there are two AR model definitions, `Account` and `Profile`, for the sake of explanation.)
65
+ Suppose you have two models:
56
66
 
57
67
  ```ruby
58
68
  class Account < ApplicationRecord
59
- has_one :profile # can work without `autosave:true`
69
+ has_one :profile
60
70
  validates :name, :email, presence: true
61
71
  end
62
72
 
@@ -66,40 +76,23 @@ class Profile < ApplicationRecord
66
76
  end
67
77
  ```
68
78
 
69
- Here is an example of designing a model that updates both Account and Profile at the same time, using `ActiveRecordCompose::Model`.
79
+ You can compose them into one form object:
70
80
 
71
81
  ```ruby
72
82
  class UserRegistration < ActiveRecordCompose::Model
73
- def initialize
83
+ def initialize(attributes = {})
74
84
  @account = Account.new
75
85
  @profile = @account.build_profile
76
-
77
- super() # Don't forget to call `super()`
78
- # RuboCop's Lint/MissingSuper cop assists in addressing this.
79
-
86
+ super(attributes)
80
87
  models << account << profile
81
- # Alternatively, it can also be written as follows:
82
- # models.push(account)
83
- # models.push(profile)
84
88
  end
85
89
 
86
- # Attribute declarations using ActiveModel::Attributes are supported.
87
90
  attribute :terms_of_service, :boolean
88
-
89
- # You can provide validation definitions limited to UserRegistration.
90
- # Instead of directly defining validations for Account or Profile, such
91
- # as `on: :create` in the context, the model itself explains the context.
92
91
  validates :terms_of_service, presence: true
93
92
  validates :email, confirmation: true
94
93
 
95
- # You can provide callback definitions limited to UserRegistration.
96
- # For example, if this is written directly in the AR model, you need to consider
97
- # callback control for data generation during tests and other situations.
98
94
  after_commit :send_email_message
99
95
 
100
- # UserRegistration behaves as if it has attributes like email, name, and age
101
- # For example, `email` is delegated to `account.email`,
102
- # and `email=` is delegated to `account.email=`.
103
96
  delegate_attribute :name, :email, to: :account
104
97
  delegate_attribute :firstname, :lastname, :age, to: :profile
105
98
 
@@ -113,12 +106,11 @@ class UserRegistration < ActiveRecordCompose::Model
113
106
  end
114
107
  ```
115
108
 
116
- The above model is used as follows.
109
+ Usage:
117
110
 
118
111
  ```ruby
112
+ # === Standalone script ===
119
113
  registration = UserRegistration.new
120
-
121
- # Atomically update Account and Profile.
122
114
  registration.update!(
123
115
  name: "foo",
124
116
  email: "bar@example.com",
@@ -128,38 +120,47 @@ registration.update!(
128
120
  email_confirmation: "bar@example.com",
129
121
  terms_of_service: true,
130
122
  )
131
- ```
132
-
133
- By executing `save`, you can simultaneously update multiple models added to `models`. Furthermore, the save operation is performed within a database transaction, ensuring atomic processing.
123
+ # `#update!` SQL log
124
+ # BEGIN immediate TRANSACTION
125
+ # INSERT INTO "accounts" ("created_at", "email", "name", "updated_at") VALUES (...
126
+ # INSERT INTO "profiles" ("account_id", "age", "created_at", "firstname", "lastname", ...
127
+ # COMMIT TRANSACTION
128
+
129
+
130
+ # === Or, in a Rails controller with strong parameters ===
131
+ class UserRegistrationsController < ApplicationController
132
+ def create
133
+ @registration = UserRegistration.new(user_registration_params)
134
+ if @registration.save
135
+ redirect_to root_path, notice: "Registered!"
136
+ else
137
+ render :new
138
+ end
139
+ end
134
140
 
135
- ```ruby
136
- user_registration.save # Atomically update Account and Profile.
137
- # In case of failure, a false value is returned.
138
- user_registration.save! # With the bang method,
139
- # an exception is raised in case of failure.
141
+ private
142
+ def user_registration_params
143
+ params.require(:user_registration).permit(
144
+ :name, :email, :firstname, :lastname, :age, :email_confirmation, :terms_of_service
145
+ )
146
+ end
147
+ end
140
148
  ```
141
149
 
142
- ### `delegate_attribute`
150
+ Both `Account` and `Profile` will be updated **atomically in one transaction**.
143
151
 
144
- In many cases, the composed models have attributes that need to be assigned before saving. `ActiveRecordCompose::Model` provides `delegate_attribute`, allowing transparent access to those attributes."
152
+ ### Attribute Delegation
153
+
154
+ `delegate_attribute` allows transparent access to attributes of inner models:
145
155
 
146
156
  ```ruby
147
- # UserRegistration behaves as if it has attributes like email, name, and age
148
- # For example, `email` is delegated to `account.email`,
149
- # and `email=` is delegated to `account.email=`.
150
- delegate_attribute :name, :email, to: :account
151
- delegate_attribute :firstname, :lastname, :age, to: :profile
157
+ delegate_attribute :name, :email, to: :account
158
+ delegate_attribute :firstname, :lastname, :age, to: :profile
152
159
  ```
153
160
 
154
- Attributes defined with `.delegate_attribute` can be accessed through `#attributes` in the same way as the original attributes defined with `.attribute`.
161
+ They are also included in `#attributes`:
155
162
 
156
163
  ```ruby
157
- registration = UserRegistration.new
158
- registration.name = "foo"
159
- registration.terms_of_service = true
160
-
161
- # Not only the email_confirmation defined with attribute,
162
- # but also the attributes defined with delegate_attribute are included.
163
164
  registration.attributes
164
165
  # => {
165
166
  # "terms_of_service" => true,
@@ -171,21 +172,21 @@ registration.attributes
171
172
  # }
172
173
  ```
173
174
 
174
- ### Promotion to model from AR-model errors
175
+ ### Unified Error Handling
175
176
 
176
- When saving a composed model with `#save`, models that are not valid with `#valid?` will obviously not be saved. As a result, the #errors information can be accessed from `ActiveRecordCompose::Model`.
177
+ Validation errors from inner models are collected into the composed model:
177
178
 
178
179
  ```ruby
179
- user_registration = UserRegistration.new
180
- user_registration.email = "foo@example.com"
181
- user_registration.email_confirmation = "BAZ@example.com"
182
- user_registration.age = 18
183
- user_registration.terms_of_service = true
180
+ user_registration = UserRegistration.new(
181
+ email: "foo@example.com",
182
+ email_confirmation: "BAZ@example.com",
183
+ age: 18,
184
+ terms_of_service: true,
185
+ )
184
186
 
185
- user_registration.save
186
- #=> false
187
+ user_registration.save # => false
187
188
 
188
- user_registration.errors.to_a
189
+ user_registration.errors.full_messages
189
190
  # => [
190
191
  # "Name can't be blank",
191
192
  # "Firstname can't be blank",
@@ -194,12 +195,10 @@ user_registration.errors.to_a
194
195
  # ]
195
196
  ```
196
197
 
197
- ### I18n
198
+ ### I18n Support
198
199
 
199
- When the `#save!` operation raises an `ActiveRecord::RecordInvalid` exception, it is necessary to have pre-existing locale definitions in order to construct i18n information correctly.
200
- The specific keys required are `activemodel.errors.messages.record_invalid` or `errors.messages.record_invalid`.
201
-
202
- (Replace `en` as appropriate in the context.)
200
+ When `#save!` raises `ActiveRecord::RecordInvalid`,
201
+ make sure you have locale entries such as:
203
202
 
204
203
  ```yaml
205
204
  en:
@@ -209,204 +208,104 @@ en:
209
208
  record_invalid: 'Validation failed: %{errors}'
210
209
  ```
211
210
 
212
- Alternatively, the following definition is also acceptable:
213
-
214
- ```yaml
215
- en:
216
- errors:
217
- messages:
218
- record_invalid: 'Validation failed: %{errors}'
219
- ```
211
+ For more complete usage patterns, see the [Sample Application](#sample-application) below.
220
212
 
221
213
  ## Advanced Usage
222
214
 
223
- ### `destroy` option
224
-
225
- By adding to the models array while specifying destroy: true, you can perform a delete instead of a save on the model at #save time.
215
+ ### Destroy Option
226
216
 
227
217
  ```ruby
228
- class AccountResignation < ActiveRecordCompose::Model
229
- def initialize(account)
230
- @account = account
231
- @profile = account.profile || account.build_profile
232
- super()
233
- models.push(account)
234
- models.push(profile, destroy: true)
235
- end
236
-
237
- before_save :set_resigned_at
238
-
239
- private
240
-
241
- attr_reader :account, :profile
242
-
243
- def set_resigned_at
244
- account.resigned_at = Time.zone.now
245
- end
246
- end
218
+ models.push(profile, destroy: true)
247
219
  ```
248
- ```ruby
249
- account = Account.last
250
220
 
251
- account.resigned_at.present? #=> nil
252
- account.profile.blank? #=> false
221
+ This deletes the model on `#save` instead of persisting it.
222
+ Conditional deletion is also supported:
253
223
 
254
- account_resignation = AccountResignation.new(account)
255
- account_resignation.save!
256
-
257
- account.reload
258
- account.resigned_at.present? #=> Tue, 02 Jan 2024 22:58:01.991008870 JST +09:00
259
- account.profile.blank? #=> true
224
+ ```ruby
225
+ models.push(profile, destroy: -> { profile_field_is_blank? })
260
226
  ```
261
227
 
262
- Conditional destroy (or save) can be written like this.
263
-
264
- ```ruby
265
- class AccountRegistration < ActiveRecordCompose::Model
266
- def initialize(account)
267
- @account = account
268
- @profile = account.profile || account.build_profile
269
- super()
270
- models.push(account)
271
-
272
- # destroy if all blank, otherwise save.
273
- models.push(profile, destroy: :profile_field_is_blank?)
274
- # Alternatively, it can also be written as follows:
275
- # models.push(profile, destroy: -> { profile_field_is_blank? })
276
- end
228
+ ### Callback ordering with `#persisted?`
277
229
 
278
- delegate_attribute :email, to: :account
279
- delegate_attribute :name, :age, to: :profile
230
+ The result of `#persisted?` determines **which callbacks are fired**:
280
231
 
281
- private
232
+ - `persisted? == false` -> create callbacks (`before_create`, `after_create`, ...)
233
+ - `persisted? == true` -> update callbacks (`before_update`, `after_update`, ...)
282
234
 
283
- attr_reader :account, :profile
284
-
285
- def profile_field_is_blank?
286
- firstname.blank? && lastname.blank? && age.blank?
287
- end
288
- end
289
- ```
290
-
291
- ### Callback ordering by `#persisted?`
292
-
293
- The behavior of `(before|after|around)_create` and `(before|after|around)_update` hooks depending on the evaluation result of `#persisted?`,
294
- either the create-related callbacks or the update-related callbacks will be triggered.
235
+ This matches the behavior of normal ActiveRecord models.
295
236
 
296
237
  ```ruby
297
238
  class ComposedModel < ActiveRecordCompose::Model
298
- # ...
299
-
300
- before_save { puts 'before_save called!' }
301
- before_create { puts 'before_create called!' }
302
- before_update { puts 'before_update called!' }
303
- after_save { puts 'after_save called!' }
304
- after_create { puts 'after_create called!' }
305
- after_update { puts 'after_update called!' }
239
+ before_save { puts "before_save" }
240
+ before_create { puts "before_create" }
241
+ before_update { puts "before_update" }
242
+ after_create { puts "after_create" }
243
+ after_update { puts "after_update" }
244
+ after_save { puts "after_save" }
306
245
 
307
246
  def persisted?
308
- # Override and return a boolish value depending on the state of the inner model.
309
- # For example, it could be transferred to the primary model to be manipulated.
310
- #
311
- # # ex.)
312
- # def persisted? = the_model.persisted?
313
- #
314
- true
247
+ account.persisted?
315
248
  end
316
249
  end
317
250
  ```
318
251
 
319
- ```ruby
320
- # when `model.persisted?` returns `true`
252
+ Example:
321
253
 
254
+ ```ruby
255
+ # When persisted? == false
322
256
  model = ComposedModel.new
323
257
 
324
- model.save # or `model.update` (the same callbacks will be triggered in all cases).
325
-
326
- # before_save called!
327
- # before_update called! # when persisted? is false, before_create hook is fired here instead.
328
- # after_update called! # when persisted? is false, after_create hook is fired here instead.
329
- # after_save called!
330
- ```
331
-
332
- ```ruby
333
- # when `model.persisted?` returns `false`
258
+ model.save
259
+ # => before_save
260
+ # => before_create
261
+ # => after_create
262
+ # => after_save
334
263
 
264
+ # When persisted? == true
335
265
  model = ComposedModel.new
266
+ def model.persisted?; true; end
336
267
 
337
- model.save # or `model.update` (the same callbacks will be triggered in all cases).
338
-
339
- # before_save called!
340
- # before_create called!
341
- # after_create called!
342
- # after_save called!
268
+ model.save
269
+ # => before_save
270
+ # => before_update
271
+ # => after_update
272
+ # => after_save
343
273
  ```
344
274
 
345
- ### `#save` with custom context option
346
-
347
- The interface remains consistent with standard ActiveModel and ActiveRecord models, so the :context option works with #save.
348
-
349
- ```ruby
350
- composed_model.valid?(:custom_context)
351
-
352
- composed_model.save(context: :custom_context)
353
- ```
275
+ ### Notes on adding models dynamically
354
276
 
355
- However, this may not be ideal from a design perspective.
356
- If your application requires complex context-specific validations, consider separating models by context.
277
+ Avoid adding `models` to the models array **after validation has already run**
278
+ (for example, inside `after_validation` or `before_save` callbacks).
357
279
 
358
280
  ```ruby
359
- class Account < ActiveRecord::Base
360
- validates :name, presence: true
361
- validates :email, presence: true
362
- validates :email, format: { with: /\.edu\z/ }, on: :education
281
+ class Example < ActiveRecordCompose::Model
282
+ before_save { models << AnotherModel.new }
363
283
  end
284
+ ```
364
285
 
365
- class Registration < ActiveRecordCompose::Model
366
- def initialize(attributes = {})
367
- models.push(@account = Account.new)
368
- super(attributes)
369
- end
370
-
371
- attribute :accept, :boolean
372
- validates :accept, presence: true, on: :education
286
+ In this case, the newly added model will **not** run validations for the current save cycle.
287
+ This may look like a bug, but it is the expected behavior: validations are only applied
288
+ to models that were registered before validation started.
373
289
 
374
- delegate_attribute :name, :email, to: :account
375
-
376
- private
290
+ We intentionally do not restrict this at the framework level, since there may be valid
291
+ advanced use cases where models are manipulated dynamically.
292
+ Instead, this behavior is documented here so that developers can make an informed decision.
377
293
 
378
- attr_reader :account
379
- end
380
- ```
381
- ```ruby
382
- r = Registration.new(name: 'foo', email: 'example@example.com', accept: false)
383
- r.valid?
384
- #=> true
385
-
386
- r.valid?(:education)
387
- #=> false
388
- r.errors.map { [_1.attribute, _1.type] }
389
- #=> [[:email, :invalid], [:accept, :blank]]
390
-
391
- r.email = 'example@example.edu'
392
- r.accept = true
393
-
394
- r.valid?(:education)
395
- #=> true
396
- r.save(context: :education)
397
- #=> true
398
- ```
294
+ ## Sample Application
399
295
 
400
- ## Sample application as an example
296
+ The sample app demonstrates a more complete usage of ActiveRecordCompose
297
+ (e.g., user registration flows involving multiple models).
298
+ It is not meant to cover every possible pattern, but can serve as a reference
299
+ for putting the library into practice.
401
300
 
402
- With Github Codespaces, it can also be run directly in the browser. Naturally, a local environment is also possible.
301
+ Try it out in your browser with GitHub Codespaces (or locally):
403
302
 
404
303
  - https://github.com/hamajyotan/active_record_compose-example
405
304
 
406
305
  ## Links
407
306
 
408
- - [Document from YARD](https://hamajyotan.github.io/active_record_compose/)
409
- - [Smart way to update multiple models simultaneously in Rails](https://dev.to/hamajyotan/smart-way-to-update-multiple-models-simultaneously-in-rails-51b6)
307
+ - [API Documentation (YARD)](https://hamajyotan.github.io/active_record_compose/)
308
+ - [Blog article introducing the concept](https://dev.to/hamajyotan/smart-way-to-update-multiple-models-simultaneously-in-rails-51b6)
410
309
 
411
310
  ## Development
412
311
 
@@ -359,6 +359,29 @@ module ActiveRecordCompose
359
359
  super
360
360
  end
361
361
 
362
+ # Returns the ID value. This value is used when passing it to the `:model` option of `form_with`, etc.
363
+ # Normally it returns nil, but it can be overridden to delegate to the containing model.
364
+ #
365
+ # @example Redefine the id method by delegating to the containing model
366
+ # class Foo < ActiveRecordCompose::Model
367
+ # def initialize(primary_model)
368
+ # @primary_model = primary_model
369
+ # # ...
370
+ # end
371
+ #
372
+ # def id
373
+ # primary_model.id
374
+ # end
375
+ #
376
+ # private
377
+ #
378
+ # attr_reader :primary_model
379
+ # end
380
+ #
381
+ # @return [Object] ID value
382
+ #
383
+ def id = nil
384
+
362
385
  private
363
386
 
364
387
  # Returns a collection of model elements to encapsulate.
@@ -20,15 +20,11 @@ module ActiveRecordCompose
20
20
  # In ActiveRecord, it is soft deprecated.
21
21
  delegate :connection, to: :ar_class
22
22
 
23
- def composite_primary_key? = false # steep:ignore
24
-
25
23
  private
26
24
 
27
25
  def ar_class = ActiveRecord::Base
28
26
  end
29
27
 
30
- def id = nil
31
-
32
28
  def trigger_transactional_callbacks? = true
33
29
  def restore_transaction_record_state(_force_restore_state = false) = nil
34
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordCompose
4
- VERSION = "0.12.0"
4
+ VERSION = "1.0.1"
5
5
  end
@@ -101,8 +101,6 @@ module ActiveRecordCompose
101
101
  extend ActiveSupport::Concern
102
102
  include ActiveRecord::Transactions
103
103
 
104
- def id: -> untyped
105
-
106
104
  module ClassMethods
107
105
  def connection: -> ActiveRecord::ConnectionAdapters::AbstractAdapter
108
106
  def lease_connection: -> ActiveRecord::ConnectionAdapters::AbstractAdapter
@@ -82,6 +82,8 @@ module ActiveRecordCompose
82
82
  def update: (Hash[attribute_name, untyped]) -> bool
83
83
  def update!: (Hash[attribute_name, untyped]) -> untyped
84
84
 
85
+ def id: -> untyped
86
+
85
87
  private
86
88
  def models: -> ComposedCollection
87
89
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - hamajyotan
@@ -15,20 +15,20 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '7.0'
18
+ version: '7.1'
19
19
  - - "<"
20
20
  - !ruby/object:Gem::Version
21
- version: '8.1'
21
+ version: '8.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: '7.0'
28
+ version: '7.1'
29
29
  - - "<"
30
30
  - !ruby/object:Gem::Version
31
- version: '8.1'
31
+ version: '8.2'
32
32
  description: activemodel form object pattern. it embraces multiple AR models and provides
33
33
  a transparent interface as if they were a single model.
34
34
  email:
@@ -81,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  requirements: []
84
- rubygems_version: 3.6.7
84
+ rubygems_version: 3.7.2
85
85
  specification_version: 4
86
86
  summary: activemodel form object pattern
87
87
  test_files: []