acts_as_ditto 1.0.0 → 1.1.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 +4 -1
- data/README.md +11 -5
- data/lib/acts_as_ditto.rb +2 -5
- data/lib/ditto/acts_as_ditto.rb +7 -1
- data/lib/ditto/duplication/duplication_context.rb +25 -0
- data/lib/ditto/{duplicator.rb → duplication/duplicator.rb} +10 -4
- data/lib/ditto/version.rb +1 -1
- metadata +7 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 77bc6854fed3d05ffcb66f3332fa1f7dc125647950c20775363d3161b7310a95
|
|
4
|
+
data.tar.gz: 95008e2cc3ea34ac91f7bd5aa7bccaf9dccc5d4d2e36df774dde2f48d127d1e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ba7776ae856f7501784af0516b85bbe3aab66479669f2fd355c3da85d6a07ef4846c5c49d9d7bcc976f9fe0f03717ee468a784b0a8747ca3d58310bf0822d46
|
|
7
|
+
data.tar.gz: 64697ab3b30ee07cd5ec49469c2cccfdca7021e7867b1e855315714c9f93617094d3c25570cb56ba5f3801834de6f72cb8aaec66381a29086a8c47f5090db735
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [1.1.0] - 2026-11-09
|
|
2
|
+
|
|
3
|
+
- Add duplication context to prevent cycle loops when cloning associtations. It tracks already duplicated records within a single `ditto` call and reuses them.
|
|
4
|
+
- `ditto!` now wraps persisting the duplicate graph in a transaction, validation failures now roll back the whole graph, not just the record that failed.
|
|
2
5
|
|
|
3
6
|
## [1.0.0] - 2026-08-28
|
|
4
7
|
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# acts_as_ditto
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Adds an `acts_as_ditto` DSL to your ActiveRecord models for duplicating
|
|
4
4
|
records with custom control
|
|
5
5
|
|
|
6
6
|
Similar to `.dup`, but with the options like resetting attributes, applying static
|
|
@@ -28,6 +28,12 @@ class Invoice < ApplicationRecord
|
|
|
28
28
|
end
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
`#ditto` builds the duplicate (and, with `clone_associations`, its whole
|
|
32
|
+
associated graph) without persisting it.
|
|
33
|
+
`#ditto!` persists that whole graph in a single transaction: if any record in
|
|
34
|
+
it fails validation, nothing is saved and an `ActiveRecord::RecordInvalid` is
|
|
35
|
+
raised.
|
|
36
|
+
|
|
31
37
|
### Duplicating associatons
|
|
32
38
|
|
|
33
39
|
Recursively duplicates the given associations along with the record.
|
|
@@ -100,15 +106,15 @@ end
|
|
|
100
106
|
|
|
101
107
|
## Inspiration
|
|
102
108
|
|
|
103
|
-
|
|
109
|
+
acts_as_ditto was inspired by [amoeba](https://github.com/amoeba-rb/amoeba), which solves the same problem with similar DSL logic.
|
|
104
110
|
|
|
105
|
-
|
|
111
|
+
acts_as_ditto is opt-in rather than opt-out: you list exactly which associations to
|
|
106
112
|
clone with `clone_associations`, instead of enabling everything and excluding
|
|
107
113
|
what you don't want.
|
|
108
114
|
|
|
109
115
|
## Contributing
|
|
110
116
|
|
|
111
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/njaeggi/acts_as_ditto. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/njaeggi/acts_as_ditto/blob/master/CODE_OF_CONDUCT.md).
|
|
117
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/njaeggi/acts_as_ditto/issues. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/njaeggi/acts_as_ditto/blob/master/CODE_OF_CONDUCT.md).
|
|
112
118
|
|
|
113
119
|
## License
|
|
114
120
|
|
data/lib/acts_as_ditto.rb
CHANGED
|
@@ -4,13 +4,10 @@ require "active_support"
|
|
|
4
4
|
|
|
5
5
|
require_relative "ditto/version"
|
|
6
6
|
require_relative "ditto/configuration"
|
|
7
|
-
require_relative "ditto/
|
|
7
|
+
require_relative "ditto/duplication/duplication_context"
|
|
8
|
+
require_relative "ditto/duplication/duplicator"
|
|
8
9
|
require_relative "ditto/acts_as_ditto"
|
|
9
10
|
|
|
10
|
-
module Ditto
|
|
11
|
-
class Error < StandardError; end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
11
|
ActiveSupport.on_load(:active_record) do
|
|
15
12
|
include Ditto::ActsAsDitto
|
|
16
13
|
end
|
data/lib/ditto/acts_as_ditto.rb
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ditto
|
|
4
|
+
# Tracks records that have already been duplicated during a single
|
|
5
|
+
# `ditto` call
|
|
6
|
+
class DuplicationContext
|
|
7
|
+
def initialize
|
|
8
|
+
@duplicates = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def duplicate_of(record)
|
|
12
|
+
@duplicates[identity_for(record)]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def register(record, duplicate)
|
|
16
|
+
@duplicates[identity_for(record)] = duplicate
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def identity_for(record)
|
|
22
|
+
record.persisted? ? [record.class.name, record.id] : record.object_id
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -3,13 +3,21 @@
|
|
|
3
3
|
module Ditto
|
|
4
4
|
# Builds a duplicate of a record based on `Ditto::Configuration`.
|
|
5
5
|
class Duplicator
|
|
6
|
-
def initialize(record, configuration)
|
|
6
|
+
def initialize(record, configuration, context = nil)
|
|
7
7
|
@record = record
|
|
8
8
|
@configuration = configuration
|
|
9
|
+
@context = context || DuplicationContext.new
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def duplicate
|
|
13
|
+
@context.duplicate_of(@record) || build_duplicate
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def build_duplicate
|
|
12
19
|
new_record = @record.dup
|
|
20
|
+
@context.register(@record, new_record)
|
|
13
21
|
|
|
14
22
|
reset_attributes_to_default(new_record)
|
|
15
23
|
nullify_attributes(new_record)
|
|
@@ -22,8 +30,6 @@ module Ditto
|
|
|
22
30
|
new_record
|
|
23
31
|
end
|
|
24
32
|
|
|
25
|
-
private
|
|
26
|
-
|
|
27
33
|
def reset_attributes_to_default(new_record)
|
|
28
34
|
@configuration.defaulted_attributes.each do
|
|
29
35
|
new_record[_1] = new_record.class.column_defaults[_1.to_s]
|
|
@@ -93,7 +99,7 @@ module Ditto
|
|
|
93
99
|
Configuration.new
|
|
94
100
|
end
|
|
95
101
|
|
|
96
|
-
self.class.new(record, configuration).duplicate
|
|
102
|
+
self.class.new(record, configuration, @context).duplicate
|
|
97
103
|
end
|
|
98
104
|
end
|
|
99
105
|
end
|
data/lib/ditto/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acts_as_ditto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Niklas Jäggi
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -41,7 +40,8 @@ files:
|
|
|
41
40
|
- lib/acts_as_ditto.rb
|
|
42
41
|
- lib/ditto/acts_as_ditto.rb
|
|
43
42
|
- lib/ditto/configuration.rb
|
|
44
|
-
- lib/ditto/
|
|
43
|
+
- lib/ditto/duplication/duplication_context.rb
|
|
44
|
+
- lib/ditto/duplication/duplicator.rb
|
|
45
45
|
- lib/ditto/version.rb
|
|
46
46
|
- sig/acts_as_ditto.rbs
|
|
47
47
|
homepage: https://github.com/njaeggi/acts_as_ditto
|
|
@@ -49,9 +49,8 @@ licenses:
|
|
|
49
49
|
- MIT
|
|
50
50
|
metadata:
|
|
51
51
|
homepage_uri: https://github.com/njaeggi/acts_as_ditto
|
|
52
|
-
source_code_uri: https://github.com/njaeggi/acts_as_ditto/tree/
|
|
53
|
-
changelog_uri: https://github.com/njaeggi/acts_as_ditto/blob/
|
|
54
|
-
post_install_message:
|
|
52
|
+
source_code_uri: https://github.com/njaeggi/acts_as_ditto/tree/master
|
|
53
|
+
changelog_uri: https://github.com/njaeggi/acts_as_ditto/blob/master/CHANGELOG.md
|
|
55
54
|
rdoc_options: []
|
|
56
55
|
require_paths:
|
|
57
56
|
- lib
|
|
@@ -66,8 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
66
65
|
- !ruby/object:Gem::Version
|
|
67
66
|
version: '0'
|
|
68
67
|
requirements: []
|
|
69
|
-
rubygems_version: 3.
|
|
70
|
-
signing_key:
|
|
68
|
+
rubygems_version: 3.6.9
|
|
71
69
|
specification_version: 4
|
|
72
70
|
summary: Configurable ActiveRecord duplication.
|
|
73
71
|
test_files: []
|