active_record_compose 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +8 -9
- data/lib/active_record_compose/attributes.rb +24 -2
- data/lib/active_record_compose/composed_collection.rb +35 -8
- data/lib/active_record_compose/exceptions.rb +44 -0
- data/lib/active_record_compose/transaction_support.rb +1 -1
- data/lib/active_record_compose/validations.rb +16 -1
- data/lib/active_record_compose/version.rb +1 -1
- data/lib/active_record_compose/wrapped_model.rb +13 -4
- data/lib/active_record_compose.rb +1 -0
- data/sig/_internal/package_private.rbs +12 -7
- data/sig/active_record_compose.rbs +11 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 810feb87760ff992aa21ca019081e6072ec43c99387ea0ee013f767d4d2c875c
|
|
4
|
+
data.tar.gz: 7077c4d5b79d12c6c5f5a0297d0d2837c3d3c79a3b8e74a13c12e05a3511c078
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 283b3beaab24fb19d30e134dbe543a25c730bf0d331bdd5114ae89747d0a247b8b572d7e6f2578c06d80f2f7cb4b8c6023f2640518c5b0dc21d335401e45ab5c
|
|
7
|
+
data.tar.gz: 6f55ebeb0bd4379d206f55b8dc8dc618beca9d281f0d425c0cc8d96078d60ed74fd26c67b92b2bb8c26f9cb6dd4634557ef1064990c4a7ca91bb15e99d6c381e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.2.1] - 2026-03-21
|
|
4
|
+
|
|
5
|
+
* Improved clarity of error when accessing uninitialized attributes.
|
|
6
|
+
(https://github.com/hamajyotan/active_record_compose/pull/71)
|
|
7
|
+
* doc: Minor document adjustments, etc.
|
|
8
|
+
|
|
9
|
+
## [1.2.0] - 2026-01-05
|
|
10
|
+
|
|
11
|
+
* Avoid issuing multiple saves on the same object.
|
|
12
|
+
(https://github.com/hamajyotan/active_record_compose/pull/56)
|
|
13
|
+
* The storage of `#models` has been changed from an Array to a Set.
|
|
14
|
+
This prevents duplicate additions of the same object and option combinations.
|
|
15
|
+
Also, `#models#delete` now deletes the model regardless of the options used when it was added.
|
|
16
|
+
(https://github.com/hamajyotan/active_record_compose/pull/57)
|
|
17
|
+
* Adding an `ActiveRecordCompose::Model` to `#models` now throws an error if there is a circular reference.
|
|
18
|
+
(https://github.com/hamajyotan/active_record_compose/pull/58)
|
|
19
|
+
|
|
3
20
|
## [1.1.1] - 2025-12-04
|
|
4
21
|
|
|
5
22
|
* fix: the save method would return nil instead of false.
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ActiveRecordCompose
|
|
2
2
|
|
|
3
3
|
ActiveRecordCompose lets you build form objects that combine multiple ActiveRecord models into a single, unified interface.
|
|
4
|
-
More than
|
|
4
|
+
More than a simple form object, ActiveRecordCompose 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.
|
|
5
5
|
|
|
6
6
|
[](https://badge.fury.io/rb/active_record_compose)
|
|
7
7
|

|
|
@@ -29,15 +29,14 @@ More than just a simple form object, it is designed as a **business-oriented com
|
|
|
29
29
|
|
|
30
30
|
## Motivation
|
|
31
31
|
|
|
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
|
+
In Rails, `ActiveRecord::Base` is responsible for persisting data to the database and modeling application behavior through validations and callbacks.
|
|
34
33
|
|
|
35
34
|
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
35
|
This mixes unrelated concerns into one model, leading to unnecessary complexity.
|
|
37
36
|
|
|
38
|
-
`ActiveModel::Model` helps
|
|
37
|
+
`ActiveModel::Model` helps address this by providing a familiar API (`attribute`, `errors`, validations, callbacks) without persistence, allowing you to isolate logic per use case.
|
|
39
38
|
|
|
40
|
-
**ActiveRecordCompose** builds on `ActiveModel::Model` and
|
|
39
|
+
**ActiveRecordCompose** builds on `ActiveModel::Model` and provides a powerful **business object** that acts as a first-class model within Rails.
|
|
41
40
|
- Transparently accesses attributes across multiple models
|
|
42
41
|
- Saves all associated models atomically in a transaction
|
|
43
42
|
- Collects and exposes error information consistently
|
|
@@ -106,7 +105,7 @@ class UserRegistration < ActiveRecordCompose::Model
|
|
|
106
105
|
end
|
|
107
106
|
```
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
Example usage:
|
|
110
109
|
|
|
111
110
|
```ruby
|
|
112
111
|
# === Standalone script ===
|
|
@@ -174,7 +173,7 @@ registration.attributes
|
|
|
174
173
|
|
|
175
174
|
### Unified Error Handling
|
|
176
175
|
|
|
177
|
-
Validation errors from inner models are collected into the composed
|
|
176
|
+
Validation errors from the inner models are collected into the composed object:
|
|
178
177
|
|
|
179
178
|
```ruby
|
|
180
179
|
user_registration = UserRegistration.new(
|
|
@@ -274,7 +273,7 @@ model.save
|
|
|
274
273
|
|
|
275
274
|
### Notes on adding models dynamically
|
|
276
275
|
|
|
277
|
-
Avoid adding
|
|
276
|
+
Avoid adding models to the `models` array **after validation has already run**
|
|
278
277
|
(for example, inside `after_validation` or `before_save` callbacks).
|
|
279
278
|
|
|
280
279
|
```ruby
|
|
@@ -323,5 +322,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
323
322
|
|
|
324
323
|
## Code of Conduct
|
|
325
324
|
|
|
326
|
-
Everyone interacting in the
|
|
325
|
+
Everyone interacting in the ActiveRecordCompose project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hamajyotan/active_record_compose/blob/main/CODE_OF_CONDUCT.md).
|
|
327
326
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "attributes/attribute_predicate"
|
|
4
4
|
require_relative "attributes/delegation"
|
|
5
5
|
require_relative "attributes/querying"
|
|
6
|
+
require_relative "exceptions"
|
|
6
7
|
|
|
7
8
|
module ActiveRecordCompose
|
|
8
9
|
# Provides attribute-related functionality for use within ActiveRecordCompose::Model.
|
|
@@ -127,7 +128,11 @@ module ActiveRecordCompose
|
|
|
127
128
|
#
|
|
128
129
|
# @see #attributes
|
|
129
130
|
# @return [Array<String>] array of attribute name.
|
|
130
|
-
def attribute_names
|
|
131
|
+
def attribute_names
|
|
132
|
+
_require_attributes_initialized do
|
|
133
|
+
super + delegated_attributes.to_a.map { _1.attribute_name }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
131
136
|
|
|
132
137
|
# Returns a hash with the attribute name as key and the attribute value as value.
|
|
133
138
|
# Attributes declared with {.delegate_attribute} are also merged.
|
|
@@ -155,7 +160,24 @@ module ActiveRecordCompose
|
|
|
155
160
|
#
|
|
156
161
|
# @return [Hash<String, Object>] hash with the attribute name as key and the attribute value as value.
|
|
157
162
|
def attributes
|
|
158
|
-
|
|
163
|
+
_require_attributes_initialized do
|
|
164
|
+
super.merge(*delegated_attributes.to_a.map { _1.attribute_hash(self) })
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
def _write_attribute(...) = _require_attributes_initialized { super } # steep:ignore
|
|
171
|
+
|
|
172
|
+
def attribute(...) = _require_attributes_initialized { super }
|
|
173
|
+
|
|
174
|
+
def _require_attributes_initialized
|
|
175
|
+
unless @attributes
|
|
176
|
+
raise ActiveRecordCompose::UninitializedAttribute,
|
|
177
|
+
"No attributes have been set. Is proper initialization performed, such as calling `super` in `initialize`?"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
yield
|
|
159
181
|
end
|
|
160
182
|
end
|
|
161
183
|
end
|
|
@@ -13,7 +13,7 @@ module ActiveRecordCompose
|
|
|
13
13
|
|
|
14
14
|
def initialize(owner)
|
|
15
15
|
@owner = owner
|
|
16
|
-
@models =
|
|
16
|
+
@models = Set.new
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# Enumerates model objects.
|
|
@@ -69,13 +69,28 @@ module ActiveRecordCompose
|
|
|
69
69
|
# Removes the specified model from the collection.
|
|
70
70
|
# Returns nil if the deletion fails, self if it succeeds.
|
|
71
71
|
#
|
|
72
|
+
# The specified model instance will be deleted regardless of the options used when it was added.
|
|
73
|
+
#
|
|
74
|
+
# @example
|
|
75
|
+
# model_a = Model.new
|
|
76
|
+
# model_b = Model.new
|
|
77
|
+
#
|
|
78
|
+
# collection.push(model_a, destroy: true)
|
|
79
|
+
# collection.push(model_b)
|
|
80
|
+
# collection.push(model_a, destroy: false)
|
|
81
|
+
# collection.count #=> 3
|
|
82
|
+
#
|
|
83
|
+
# collection.delete(model_a)
|
|
84
|
+
# collection.count #=> 1
|
|
85
|
+
#
|
|
72
86
|
# @param model [Object] model instance
|
|
73
87
|
# @return [self] Successful deletion
|
|
74
88
|
# @return [nil] If deletion fails
|
|
75
89
|
def delete(model)
|
|
76
|
-
|
|
77
|
-
return nil
|
|
90
|
+
matched = models.select { _1.__raw_model == model }
|
|
91
|
+
return nil if matched.blank?
|
|
78
92
|
|
|
93
|
+
matched.each { models.delete(_1) }
|
|
79
94
|
self
|
|
80
95
|
end
|
|
81
96
|
|
|
@@ -87,17 +102,27 @@ module ActiveRecordCompose
|
|
|
87
102
|
# @private
|
|
88
103
|
def wrap(model, destroy: false, if: nil)
|
|
89
104
|
if destroy.is_a?(Symbol)
|
|
90
|
-
|
|
91
|
-
destroy = -> { owner.__send__(method) }
|
|
105
|
+
destroy = symbol_proc_map[destroy]
|
|
92
106
|
end
|
|
107
|
+
|
|
93
108
|
if_option = binding.local_variable_get(:if)
|
|
94
109
|
if if_option.is_a?(Symbol)
|
|
95
|
-
|
|
96
|
-
if_option = -> { owner.__send__(method) }
|
|
110
|
+
if_option = symbol_proc_map[if_option]
|
|
97
111
|
end
|
|
112
|
+
|
|
98
113
|
ActiveRecordCompose::WrappedModel.new(model, destroy:, if: if_option)
|
|
99
114
|
end
|
|
100
115
|
|
|
116
|
+
# @private
|
|
117
|
+
def symbol_proc_map
|
|
118
|
+
@symbol_proc_map ||=
|
|
119
|
+
Hash.new do |h, k|
|
|
120
|
+
h[k] = -> { owner.__send__(k) }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def instance_variables_to_inspect = %i[@owner @models]
|
|
125
|
+
|
|
101
126
|
# @private
|
|
102
127
|
module PackagePrivate
|
|
103
128
|
refine ComposedCollection do
|
|
@@ -105,7 +130,9 @@ module ActiveRecordCompose
|
|
|
105
130
|
#
|
|
106
131
|
# @private
|
|
107
132
|
# @return [Array[WrappedModel]] array of wrapped model instance.
|
|
108
|
-
def __wrapped_models
|
|
133
|
+
def __wrapped_models
|
|
134
|
+
models.reject { _1.ignore? }.uniq { [ _1.__raw_model, !!_1.destroy_context? ] }.select { _1.__raw_model }
|
|
135
|
+
end
|
|
109
136
|
end
|
|
110
137
|
end
|
|
111
138
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecordCompose
|
|
4
|
+
# Occurs when a circular reference is detected in the containing model.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# class Model < ActiveRecordCompose::Model
|
|
8
|
+
# def initialize
|
|
9
|
+
# super()
|
|
10
|
+
# models << self # Adding itself to models creates a circular reference.
|
|
11
|
+
# end
|
|
12
|
+
# end
|
|
13
|
+
# model = Model.new
|
|
14
|
+
# model.save #=> raises ActiveRecordCompose::CircularReferenceDetected
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# class Model < ActiveRecordCompose::Model
|
|
18
|
+
# attribute :model
|
|
19
|
+
# before_validation { models << model }
|
|
20
|
+
# end
|
|
21
|
+
# inner = Model.new
|
|
22
|
+
# middle = Model.new(model: inner)
|
|
23
|
+
# outer = Model.new(model: middle)
|
|
24
|
+
#
|
|
25
|
+
# inner.model = outer # There is a circular reference in the form outer > middle > inner > outer.
|
|
26
|
+
# outer.save #=> raises ActiveRecordCompose::CircularReferenceDetected
|
|
27
|
+
#
|
|
28
|
+
class CircularReferenceDetected < StandardError; end
|
|
29
|
+
|
|
30
|
+
# Occurs when accessing Attributes without initializing it.
|
|
31
|
+
#
|
|
32
|
+
# @example
|
|
33
|
+
# class Model < ActiveRecordCompose::Model
|
|
34
|
+
# def initialize
|
|
35
|
+
# # Intentionally not calling super...
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# attribute :foo
|
|
39
|
+
# end
|
|
40
|
+
# model = Model.new
|
|
41
|
+
# model.foo = 1 #=> raises ActiveRecordCompose::UninitializedAttribute
|
|
42
|
+
#
|
|
43
|
+
class UninitializedAttribute < StandardError; end
|
|
44
|
+
end
|
|
@@ -113,7 +113,7 @@ module ActiveRecordCompose
|
|
|
113
113
|
ensure_finalize = !connection.transaction_open?
|
|
114
114
|
|
|
115
115
|
connection.transaction do
|
|
116
|
-
connection.add_transaction_record(self, ensure_finalize || has_transactional_callbacks?)
|
|
116
|
+
connection.add_transaction_record(self, ensure_finalize || has_transactional_callbacks?)
|
|
117
117
|
|
|
118
118
|
yield.tap { raise ActiveRecord::Rollback unless _1 }
|
|
119
119
|
end || false
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "composed_collection"
|
|
4
|
+
require_relative "exceptions"
|
|
4
5
|
|
|
5
6
|
module ActiveRecordCompose
|
|
6
7
|
using ComposedCollection::PackagePrivate
|
|
@@ -44,7 +45,7 @@ module ActiveRecordCompose
|
|
|
44
45
|
# Returns the `ActiveModel::Errors` object that holds all information about attribute error messages.
|
|
45
46
|
#
|
|
46
47
|
# The `ActiveModel::Base` implementation itself,
|
|
47
|
-
# but also aggregates error information for objects stored in {#models} when validation is performed.
|
|
48
|
+
# but also aggregates error information for objects stored in {ActiveRecordCompose::Model#models} when validation is performed.
|
|
48
49
|
#
|
|
49
50
|
# class Account < ActiveRecord::Base
|
|
50
51
|
# validates :name, :email, presence: true
|
|
@@ -76,10 +77,24 @@ module ActiveRecordCompose
|
|
|
76
77
|
#
|
|
77
78
|
# @return [ActiveModel::Errors]
|
|
78
79
|
|
|
80
|
+
# @private
|
|
81
|
+
def detect_circular_reference(targets = [])
|
|
82
|
+
raise CircularReferenceDetected if targets.include?(object_id)
|
|
83
|
+
|
|
84
|
+
targets += [ object_id ]
|
|
85
|
+
# steep:ignore:start
|
|
86
|
+
models.select { _1.respond_to?(:detect_circular_reference) }.each do |m|
|
|
87
|
+
m.detect_circular_reference(targets)
|
|
88
|
+
end
|
|
89
|
+
# steep:ignore:end
|
|
90
|
+
end
|
|
91
|
+
|
|
79
92
|
private
|
|
80
93
|
|
|
81
94
|
# @private
|
|
82
95
|
def validate_models
|
|
96
|
+
detect_circular_reference
|
|
97
|
+
|
|
83
98
|
context = override_validation_context
|
|
84
99
|
models.__wrapped_models.lazy.select { _1.invalid?(context) }.each { errors.merge!(_1) }
|
|
85
100
|
end
|
|
@@ -104,19 +104,28 @@ module ActiveRecordCompose
|
|
|
104
104
|
# @param [Object] other
|
|
105
105
|
# @return [Boolean]
|
|
106
106
|
def ==(other)
|
|
107
|
+
return true if equal?(other)
|
|
107
108
|
return false unless self.class == other.class
|
|
108
|
-
return false unless model == other.model
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
equality_key == other.equality_key
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
+
def eql?(other)
|
|
114
|
+
return true if equal?(other)
|
|
115
|
+
return false unless self.class == other.class
|
|
116
|
+
|
|
117
|
+
equality_key.eql?(other.equality_key)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def hash = equality_key.hash
|
|
121
|
+
|
|
113
122
|
protected
|
|
114
123
|
|
|
115
|
-
|
|
124
|
+
def equality_key = [ model, destroy_context_type, if_option ]
|
|
116
125
|
|
|
117
126
|
private
|
|
118
127
|
|
|
119
|
-
attr_reader :destroy_context_type, :if_option
|
|
128
|
+
attr_reader :model, :destroy_context_type, :if_option
|
|
120
129
|
|
|
121
130
|
# @private
|
|
122
131
|
module PackagePrivate
|
|
@@ -11,6 +11,9 @@ module ActiveRecordCompose
|
|
|
11
11
|
|
|
12
12
|
@attributes: untyped
|
|
13
13
|
|
|
14
|
+
private
|
|
15
|
+
def _require_attributes_initialized: [T] () { () -> T } -> T
|
|
16
|
+
|
|
14
17
|
class AttributePredicate
|
|
15
18
|
def initialize: (untyped value) -> void
|
|
16
19
|
def call: -> bool
|
|
@@ -64,16 +67,20 @@ module ActiveRecordCompose
|
|
|
64
67
|
class ComposedCollection
|
|
65
68
|
def initialize: (Model) -> void
|
|
66
69
|
|
|
70
|
+
@symbol_proc_map: Hash[Symbol, (destroy_context_type | condition_type)]
|
|
71
|
+
|
|
67
72
|
private
|
|
68
73
|
attr_reader owner: Model
|
|
69
|
-
attr_reader models:
|
|
74
|
+
attr_reader models: Set[WrappedModel]
|
|
70
75
|
def wrap: (ar_like, ?destroy: (bool | Symbol | destroy_context_type), ?if: (nil | Symbol | condition_type)) -> WrappedModel
|
|
76
|
+
def symbol_proc_map: () -> Hash[Symbol, (destroy_context_type | condition_type)]
|
|
77
|
+
def instance_variables_to_inspect: () -> Array[Symbol]
|
|
71
78
|
|
|
72
79
|
module PackagePrivate
|
|
73
|
-
def __wrapped_models: () ->
|
|
80
|
+
def __wrapped_models: () -> Enumerable[WrappedModel]
|
|
74
81
|
|
|
75
82
|
private
|
|
76
|
-
def models: () ->
|
|
83
|
+
def models: () -> Set[WrappedModel]
|
|
77
84
|
end
|
|
78
85
|
|
|
79
86
|
include PackagePrivate
|
|
@@ -143,10 +150,6 @@ module ActiveRecordCompose
|
|
|
143
150
|
def raise_on_save_error_message: -> String
|
|
144
151
|
end
|
|
145
152
|
|
|
146
|
-
class Railtie < Rails::Railtie
|
|
147
|
-
extend Rails::Initializable::ClassMethods
|
|
148
|
-
end
|
|
149
|
-
|
|
150
153
|
module Validations : Model
|
|
151
154
|
extend ActiveSupport::Concern
|
|
152
155
|
extend ActiveModel::Validations::ClassMethods
|
|
@@ -154,6 +157,7 @@ module ActiveRecordCompose
|
|
|
154
157
|
def save: (**untyped options) -> bool
|
|
155
158
|
def save!: (**untyped options) -> untyped
|
|
156
159
|
def valid?: (?validation_context context) -> bool
|
|
160
|
+
def detect_circular_reference: (?Array[Integer])-> untyped
|
|
157
161
|
|
|
158
162
|
@context_for_override_validation: OverrideValidationContext
|
|
159
163
|
|
|
@@ -187,6 +191,7 @@ module ActiveRecordCompose
|
|
|
187
191
|
attr_reader model: ar_like
|
|
188
192
|
attr_reader destroy_context_type: (bool | destroy_context_type)
|
|
189
193
|
attr_reader if_option: (nil | condition_type)
|
|
194
|
+
def equality_key: () -> [ar_like, (bool | destroy_context_type), (nil | condition_type)]
|
|
190
195
|
|
|
191
196
|
module PackagePrivate
|
|
192
197
|
def __raw_model: () -> ar_like
|
|
@@ -47,6 +47,9 @@ module ActiveRecordCompose
|
|
|
47
47
|
def delete: (ar_like) -> ComposedCollection?
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
class CircularReferenceDetected < StandardError
|
|
51
|
+
end
|
|
52
|
+
|
|
50
53
|
class Model
|
|
51
54
|
include ActiveModel::Model
|
|
52
55
|
include ActiveModel::Validations::Callbacks
|
|
@@ -68,6 +71,7 @@ module ActiveRecordCompose
|
|
|
68
71
|
def self.around_update: (*around_callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
|
69
72
|
def self.after_update: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
|
70
73
|
|
|
74
|
+
def self.before_commit: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
|
71
75
|
def self.after_commit: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
|
72
76
|
def self.after_rollback: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
|
73
77
|
|
|
@@ -90,4 +94,11 @@ module ActiveRecordCompose
|
|
|
90
94
|
private
|
|
91
95
|
def models: -> ComposedCollection
|
|
92
96
|
end
|
|
97
|
+
|
|
98
|
+
class Railtie < Rails::Railtie
|
|
99
|
+
extend Rails::Initializable::ClassMethods
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class UninitializedAttribute < StandardError
|
|
103
|
+
end
|
|
93
104
|
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: 1.
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- hamajyotan
|
|
@@ -50,6 +50,7 @@ files:
|
|
|
50
50
|
- lib/active_record_compose/attributes/querying.rb
|
|
51
51
|
- lib/active_record_compose/callbacks.rb
|
|
52
52
|
- lib/active_record_compose/composed_collection.rb
|
|
53
|
+
- lib/active_record_compose/exceptions.rb
|
|
53
54
|
- lib/active_record_compose/inspectable.rb
|
|
54
55
|
- lib/active_record_compose/model.rb
|
|
55
56
|
- lib/active_record_compose/persistence.rb
|
|
@@ -83,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
83
84
|
- !ruby/object:Gem::Version
|
|
84
85
|
version: '0'
|
|
85
86
|
requirements: []
|
|
86
|
-
rubygems_version:
|
|
87
|
+
rubygems_version: 4.0.3
|
|
87
88
|
specification_version: 4
|
|
88
89
|
summary: activemodel form object pattern
|
|
89
90
|
test_files: []
|