active_record_compose 1.2.0 → 1.3.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 +14 -0
- data/README.md +12 -9
- data/lib/active_record_compose/attributes.rb +24 -2
- data/lib/active_record_compose/composed_collection.rb +2 -1
- data/lib/active_record_compose/exceptions.rb +15 -0
- data/lib/active_record_compose/transaction_support/active_transaction.rb +42 -0
- data/lib/active_record_compose/transaction_support/transaction_coordinator.rb +47 -0
- data/lib/active_record_compose/transaction_support.rb +41 -13
- data/lib/active_record_compose/validations.rb +2 -1
- data/lib/active_record_compose/version.rb +1 -1
- data/sig/_internal/package_private.rbs +22 -0
- data/sig/active_record_compose.rbs +3 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 148413ab669022c937e7f4775cff13dc018c9ba190014b130c10b9ca7e767a3f
|
|
4
|
+
data.tar.gz: 51ec332dcf2decf04dfb7f3bf8f0d38bf791d36d960d0d19c388608ef3f33a32
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7db6b03f1a56d9d9d1ef0427362b65966bcfca997a465c4ce843d5dad9c4237e43b443ce0620629c665ab09163bf46fd362976009c2e426ae40849c1a41d18bd
|
|
7
|
+
data.tar.gz: 43ecb29b976c4136650e2152f1533af7e06de40afeba68f7265e97ba6eff208165271c338b4348d44127d850ebe75de2908eea60a18e986ef47e181d95d6e784
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.3.0] - 2026-08-09
|
|
4
|
+
|
|
5
|
+
* Support secondary and multiple database
|
|
6
|
+
(https://github.com/hamajyotan/active_record_compose/pull/74)
|
|
7
|
+
- When models connecting to different databases are used together, the system behaves in a manner simulating a two-phase commit.
|
|
8
|
+
- Due to the nature of the ActiveRecord API supported by Rails, a true two-phase commit is not implemented; instead, transactions are nested when multiple database connections are involved.
|
|
9
|
+
- Note that operations remain unchanged when all models belong to a single primary database.
|
|
10
|
+
|
|
11
|
+
## [1.2.1] - 2026-03-21
|
|
12
|
+
|
|
13
|
+
* Improved clarity of error when accessing uninitialized attributes.
|
|
14
|
+
(https://github.com/hamajyotan/active_record_compose/pull/71)
|
|
15
|
+
* doc: Minor document adjustments, etc.
|
|
16
|
+
|
|
3
17
|
## [1.2.0] - 2026-01-05
|
|
4
18
|
|
|
5
19
|
* Avoid issuing multiple saves on the same object.
|
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
|
|
@@ -60,6 +59,10 @@ $ bundle
|
|
|
60
59
|
|
|
61
60
|
## Quick Start
|
|
62
61
|
|
|
62
|
+
For a complete runnable application, see the Sample Application section below.
|
|
63
|
+
|
|
64
|
+
The examples in this section focus on ActiveRecordCompose itself and intentionally omit surrounding application code such as migrations, routes, views, and jobs.
|
|
65
|
+
|
|
63
66
|
### Basic Example
|
|
64
67
|
|
|
65
68
|
Suppose you have two models:
|
|
@@ -106,7 +109,7 @@ class UserRegistration < ActiveRecordCompose::Model
|
|
|
106
109
|
end
|
|
107
110
|
```
|
|
108
111
|
|
|
109
|
-
|
|
112
|
+
Example usage:
|
|
110
113
|
|
|
111
114
|
```ruby
|
|
112
115
|
# === Standalone script ===
|
|
@@ -174,7 +177,7 @@ registration.attributes
|
|
|
174
177
|
|
|
175
178
|
### Unified Error Handling
|
|
176
179
|
|
|
177
|
-
Validation errors from inner models are collected into the composed
|
|
180
|
+
Validation errors from the inner models are collected into the composed object:
|
|
178
181
|
|
|
179
182
|
```ruby
|
|
180
183
|
user_registration = UserRegistration.new(
|
|
@@ -274,7 +277,7 @@ model.save
|
|
|
274
277
|
|
|
275
278
|
### Notes on adding models dynamically
|
|
276
279
|
|
|
277
|
-
Avoid adding
|
|
280
|
+
Avoid adding models to the `models` array **after validation has already run**
|
|
278
281
|
(for example, inside `after_validation` or `before_save` callbacks).
|
|
279
282
|
|
|
280
283
|
```ruby
|
|
@@ -323,5 +326,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
323
326
|
|
|
324
327
|
## Code of Conduct
|
|
325
328
|
|
|
326
|
-
Everyone interacting in the
|
|
329
|
+
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
330
|
|
|
@@ -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
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "set"
|
|
3
4
|
require_relative "wrapped_model"
|
|
4
5
|
|
|
5
6
|
module ActiveRecordCompose
|
|
@@ -117,7 +118,7 @@ module ActiveRecordCompose
|
|
|
117
118
|
def symbol_proc_map
|
|
118
119
|
@symbol_proc_map ||=
|
|
119
120
|
Hash.new do |h, k|
|
|
120
|
-
h[k] = -> { owner.__send__(k) }
|
|
121
|
+
h[k] = -> { owner.__send__(k) } # steep:ignore
|
|
121
122
|
end
|
|
122
123
|
end
|
|
123
124
|
|
|
@@ -26,4 +26,19 @@ module ActiveRecordCompose
|
|
|
26
26
|
# outer.save #=> raises ActiveRecordCompose::CircularReferenceDetected
|
|
27
27
|
#
|
|
28
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
|
|
29
44
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecordCompose
|
|
4
|
+
module TransactionSupport
|
|
5
|
+
# @private
|
|
6
|
+
# steep:ignore:start
|
|
7
|
+
|
|
8
|
+
# In older versions, the ActiveRecord::Transaction object is not passed to the block argument of #transaction.
|
|
9
|
+
# So instead, we define a transaction object that can be evaluated equivalently.
|
|
10
|
+
# This follow-up will no longer be necessary when support for Rails 7.1 is dropped.
|
|
11
|
+
#
|
|
12
|
+
class ActiveTransaction
|
|
13
|
+
def initialize(transaction)
|
|
14
|
+
@real_transaction = transaction
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :real_transaction
|
|
18
|
+
|
|
19
|
+
def open? = !closed?
|
|
20
|
+
|
|
21
|
+
def closed? = real_transaction&.state&.completed?
|
|
22
|
+
|
|
23
|
+
def ==(other)
|
|
24
|
+
return true if equal?(other)
|
|
25
|
+
return false unless self.class == other.class
|
|
26
|
+
|
|
27
|
+
real_transaction == other.real_transaction
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def eql?(other)
|
|
31
|
+
return true if equal?(other)
|
|
32
|
+
return false unless self.class == other.class
|
|
33
|
+
|
|
34
|
+
real_transaction.eql?(other.real_transaction)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def hash = real_transaction.hash
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# steep:ignore:end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module ActiveRecordCompose
|
|
6
|
+
module TransactionSupport
|
|
7
|
+
# @private
|
|
8
|
+
class TransactionCoordinator
|
|
9
|
+
def add_transaction(active_transaction)
|
|
10
|
+
transactions << active_transaction
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# The before_commit callback is controlled so that
|
|
14
|
+
# it runs just before the outermost transaction commits,
|
|
15
|
+
# but not just before any inner transactions commit.
|
|
16
|
+
#
|
|
17
|
+
def on_before_comitted
|
|
18
|
+
return if @_before_committed_called
|
|
19
|
+
|
|
20
|
+
yield
|
|
21
|
+
@_before_committed_called = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# It processes after_commit/after_rollback only immediately
|
|
25
|
+
# after all transactions are closed.
|
|
26
|
+
#
|
|
27
|
+
def on_after_transaction
|
|
28
|
+
return unless all_finished?
|
|
29
|
+
|
|
30
|
+
with_transaction_cleanup { yield }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def with_transaction_cleanup
|
|
36
|
+
yield
|
|
37
|
+
ensure
|
|
38
|
+
@_before_committed_called = false
|
|
39
|
+
transactions.reject! { _1.closed? }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def all_finished? = transactions.all? { _1.closed? }
|
|
43
|
+
|
|
44
|
+
def transactions = @transactions ||= Set.new
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/module"
|
|
4
|
+
require_relative "transaction_support/active_transaction"
|
|
5
|
+
require_relative "transaction_support/transaction_coordinator"
|
|
4
6
|
|
|
5
7
|
module ActiveRecordCompose
|
|
6
8
|
module TransactionSupport
|
|
@@ -86,17 +88,17 @@ module ActiveRecordCompose
|
|
|
86
88
|
|
|
87
89
|
# @private
|
|
88
90
|
def before_committed!
|
|
89
|
-
_run_before_commit_callbacks
|
|
91
|
+
transaction_coordinator.on_before_comitted { _run_before_commit_callbacks }
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
# @private
|
|
93
95
|
def committed!(should_run_callbacks: true)
|
|
94
|
-
_run_commit_callbacks if should_run_callbacks
|
|
96
|
+
transaction_coordinator.on_after_transaction { _run_commit_callbacks if should_run_callbacks }
|
|
95
97
|
end
|
|
96
98
|
|
|
97
99
|
# @private
|
|
98
100
|
def rolledback!(force_restore_state: false, should_run_callbacks: true)
|
|
99
|
-
_run_rollback_callbacks if should_run_callbacks
|
|
101
|
+
transaction_coordinator.on_after_transaction { _run_rollback_callbacks if should_run_callbacks }
|
|
100
102
|
end
|
|
101
103
|
end
|
|
102
104
|
|
|
@@ -104,23 +106,49 @@ module ActiveRecordCompose
|
|
|
104
106
|
|
|
105
107
|
def save!(**options) = with_transaction_returning_status { super }
|
|
106
108
|
|
|
107
|
-
private
|
|
108
|
-
|
|
109
109
|
# @private
|
|
110
|
-
def
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
def connection_pools
|
|
111
|
+
pools =
|
|
112
|
+
models.compact.flat_map do |model|
|
|
113
|
+
if model.is_a?(ActiveRecordCompose::TransactionSupport)
|
|
114
|
+
model.connection_pools
|
|
115
|
+
elsif model.is_a?(ActiveRecord::Base)
|
|
116
|
+
connection_pool(ar_class: model.class)
|
|
117
|
+
else
|
|
118
|
+
[] # : Array[ActiveRecord::ConnectionAdapters::ConnectionPool]
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
pools << connection_pool if pools.blank?
|
|
122
|
+
pools.uniq
|
|
123
|
+
end
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
connection.add_transaction_record(self, ensure_finalize || has_transactional_callbacks?) # steep:ignore
|
|
125
|
+
private
|
|
117
126
|
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
# @private
|
|
128
|
+
def with_transaction_returning_status(&block)
|
|
129
|
+
procs = connection_pools.inject(block) do |inner_proc, pool|
|
|
130
|
+
-> do
|
|
131
|
+
pool.with_connection do |connection|
|
|
132
|
+
with_pool_transaction_isolation_level(connection) do
|
|
133
|
+
ensure_finalize = !connection.transaction_open?
|
|
134
|
+
|
|
135
|
+
connection.transaction do |tran|
|
|
136
|
+
tran ||= ActiveTransaction.new(connection.current_transaction) # steep:ignore
|
|
137
|
+
transaction_coordinator.add_transaction(tran)
|
|
138
|
+
connection.add_transaction_record(self, ensure_finalize || has_transactional_callbacks?)
|
|
139
|
+
|
|
140
|
+
inner_proc.call.tap { raise ActiveRecord::Rollback unless _1 }
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
120
144
|
end
|
|
121
145
|
end
|
|
146
|
+
procs.call || false
|
|
122
147
|
end
|
|
123
148
|
|
|
149
|
+
# @private
|
|
150
|
+
def transaction_coordinator = @transaction_coordinator ||= TransactionCoordinator.new
|
|
151
|
+
|
|
124
152
|
# @private
|
|
125
153
|
def default_ar_class = ActiveRecord::Base
|
|
126
154
|
|
|
@@ -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
|
|
@@ -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
|
|
@@ -115,6 +118,8 @@ module ActiveRecordCompose
|
|
|
115
118
|
include ActiveSupport::Callbacks
|
|
116
119
|
extend ActiveSupport::Callbacks::ClassMethods
|
|
117
120
|
|
|
121
|
+
@transaction_coordinator: ActiveRecordCompose::TransactionSupport::TransactionCoordinator
|
|
122
|
+
|
|
118
123
|
def self.before_commit: (*untyped) -> untyped
|
|
119
124
|
def self.after_commit: (*untyped) -> untyped
|
|
120
125
|
def self.after_rollback: (*untyped) -> untyped
|
|
@@ -124,11 +129,28 @@ module ActiveRecordCompose
|
|
|
124
129
|
def _run_before_commit_callbacks: () -> untyped
|
|
125
130
|
def _run_commit_callbacks: () -> untyped
|
|
126
131
|
def _run_rollback_callbacks: () -> untyped
|
|
132
|
+
def connection_pools: () -> Array[ActiveRecord::ConnectionAdapters::ConnectionPool]
|
|
127
133
|
|
|
128
134
|
private
|
|
135
|
+
def models: -> ComposedCollection
|
|
129
136
|
def default_ar_class: -> singleton(ActiveRecord::Base)
|
|
130
137
|
def connection_pool: (?ar_class: singleton(ActiveRecord::Base)) -> ActiveRecord::ConnectionAdapters::ConnectionPool
|
|
131
138
|
def with_pool_transaction_isolation_level: [T] (ActiveRecord::ConnectionAdapters::AbstractAdapter) { () -> T } -> T
|
|
139
|
+
def transaction_coordinator: () -> ActiveRecordCompose::TransactionSupport::TransactionCoordinator
|
|
140
|
+
|
|
141
|
+
class TransactionCoordinator
|
|
142
|
+
@_before_committed_called: bool
|
|
143
|
+
@transactions: Set[ActiveRecord::ConnectionAdapters::Transaction]
|
|
144
|
+
|
|
145
|
+
def add_transaction: (ActiveRecord::ConnectionAdapters::Transaction) -> void
|
|
146
|
+
def on_after_transaction: () { () -> void } -> void
|
|
147
|
+
def on_before_comitted: () { () -> void } -> void
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
def all_finished?: -> bool
|
|
151
|
+
def transactions: () -> Set[ActiveRecord::ConnectionAdapters::Transaction]
|
|
152
|
+
def with_transaction_cleanup: () { () -> void } -> void
|
|
153
|
+
end
|
|
132
154
|
end
|
|
133
155
|
|
|
134
156
|
module Persistence
|
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.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- hamajyotan
|
|
@@ -56,6 +56,8 @@ files:
|
|
|
56
56
|
- lib/active_record_compose/persistence.rb
|
|
57
57
|
- lib/active_record_compose/railtie.rb
|
|
58
58
|
- lib/active_record_compose/transaction_support.rb
|
|
59
|
+
- lib/active_record_compose/transaction_support/active_transaction.rb
|
|
60
|
+
- lib/active_record_compose/transaction_support/transaction_coordinator.rb
|
|
59
61
|
- lib/active_record_compose/validations.rb
|
|
60
62
|
- lib/active_record_compose/version.rb
|
|
61
63
|
- lib/active_record_compose/wrapped_model.rb
|
|
@@ -84,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
86
|
- !ruby/object:Gem::Version
|
|
85
87
|
version: '0'
|
|
86
88
|
requirements: []
|
|
87
|
-
rubygems_version: 4.0.
|
|
89
|
+
rubygems_version: 4.0.16
|
|
88
90
|
specification_version: 4
|
|
89
91
|
summary: activemodel form object pattern
|
|
90
92
|
test_files: []
|