deep_cloneable 1.4.0 → 3.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 +7 -0
- data/Appraisals +57 -0
- data/CHANGELOG.md +350 -0
- data/Gemfile +8 -7
- data/Gemfile.lock +51 -91
- data/LICENSE +1 -1
- data/Rakefile +8 -33
- data/deep_cloneable.gemspec +18 -55
- data/init.rb +3 -1
- data/lib/deep_cloneable/association_not_found_exception.rb +6 -0
- data/lib/deep_cloneable/deep_clone.rb +207 -0
- data/lib/deep_cloneable/skip_validations.rb +10 -0
- data/lib/deep_cloneable/version.rb +3 -0
- data/lib/deep_cloneable.rb +13 -124
- data/readme.md +242 -0
- metadata +33 -67
- data/.document +0 -5
- data/README.rdoc +0 -78
- data/VERSION +0 -1
- data/test/database.yml +0 -6
- data/test/schema.rb +0 -52
- data/test/test_deep_cloneable.rb +0 -162
- data/test/test_helper.rb +0 -79
data/readme.md
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
# deep_cloneable
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
This gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations. It is a rails 3+ upgrade of the [deep_cloning plugin](http://github.com/openminds/deep_cloning).
|
6
|
+
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
- Ruby 2.3.0, 2.4.4, 2.5.5, 2.6.3, 2.7.5, 3.3.5 (tested)
|
10
|
+
- Activerecord 3.2, 4.0, 4.1, 4.2, 5.0, 5.1, 5.2, 6.0, 7.0, 8.0 (tested)
|
11
|
+
- Rails 2.x/3.0 users, please check out the 'rails2.x-3.0' branch
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
- Add deep_cloneable to your Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'deep_cloneable', '~> 3.2.1'
|
19
|
+
```
|
20
|
+
|
21
|
+
## Upgrade details
|
22
|
+
|
23
|
+
### Upgrading from v2
|
24
|
+
|
25
|
+
There are two breaking changes that you might need to pay attention to:
|
26
|
+
|
27
|
+
- When using an optional block (see below), the block used to be evaluated before `deep_cloneable` had performed its changes (inclusions, exclusions, includes). In v3, the block is evaluated after all processing has been done, just before the copy is about to be returned.
|
28
|
+
- When a defined association is not found, `deep_cloneable` raises an exception. The exception class has changed namespace: the class definition used to be `ActiveRecord::Base::DeepCloneable::AssociationNotFoundException` and this has changed to `DeepCloneable::AssociationNotFoundException`.
|
29
|
+
|
30
|
+
### Upgrading from v1
|
31
|
+
|
32
|
+
The `dup` method with arguments has been replaced in deep_cloneable 2 by the method `deep_clone`. Please update your sources accordingly.
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
The `deep_clone` method supports a couple options that can be specified by passing an options hash. Without options, the behaviour is the same as ActiveRecord's [`dup`](http://apidock.com/rails/ActiveRecord/Core/dup) method.
|
37
|
+
|
38
|
+
### Association inclusion
|
39
|
+
|
40
|
+
Associations to be included in the dup can be specified with the `include` option:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# Single include
|
44
|
+
pirate.deep_clone include: :mateys
|
45
|
+
|
46
|
+
# Multiple includes
|
47
|
+
pirate.deep_clone include: [ :mateys, :treasures ]
|
48
|
+
|
49
|
+
# Deep includes
|
50
|
+
pirate.deep_clone include: { treasures: :gold_pieces }
|
51
|
+
pirate.deep_clone include: [ :mateys, { treasures: :gold_pieces } ]
|
52
|
+
|
53
|
+
# Disable validation for a performance speedup when saving the dup
|
54
|
+
pirate.deep_clone include: { treasures: :gold_pieces }, validate: false
|
55
|
+
|
56
|
+
# Conditional includes
|
57
|
+
pirate.deep_clone include: [
|
58
|
+
{
|
59
|
+
treasures: { gold_pieces: { if: lambda{|piece| piece.is_a?(Parrot) } } } },
|
60
|
+
mateys: { unless: lambda{|matey| matey.is_a?(GoldPiece) }
|
61
|
+
}
|
62
|
+
]
|
63
|
+
|
64
|
+
ship.deep_clone include: [
|
65
|
+
pirates: [ :treasures, :mateys, if: lambda {|pirate| pirate.name == 'Jack Sparrow' } ]
|
66
|
+
]
|
67
|
+
```
|
68
|
+
|
69
|
+
#### The Dictionary (Object Reusage)
|
70
|
+
|
71
|
+
The dictionary ensures that models are not duped multiple times when it is associated to nested models. It does this by storing a mapping of the original object to its duped object. It can be used as follows:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# Enables the dictionary (empty on initialization)
|
75
|
+
pirate.deep_clone include: [ :mateys, { treasures: [ :matey, :gold_pieces ] } ], use_dictionary: true
|
76
|
+
|
77
|
+
# Deep clones with a prefilled dictionary
|
78
|
+
dictionary = { mateys: {} }
|
79
|
+
pirate.mateys.each{|m| dict[:mateys][m] = m.deep_clone }
|
80
|
+
pirate.deep_clone include: [ :mateys, { treasures: [ :matey, :gold_pieces ] } ], dictionary: dictionary
|
81
|
+
```
|
82
|
+
|
83
|
+
### Attribute Exceptions & Inclusions
|
84
|
+
|
85
|
+
The `deep_clone` method supports both `except` and `only` for specifying which attributes should be duped:
|
86
|
+
|
87
|
+
#### Exceptions
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
# Single exception
|
91
|
+
pirate.deep_clone except: :name
|
92
|
+
|
93
|
+
# Multiple exceptions
|
94
|
+
pirate.deep_clone except: [ :name, :nick_name ]
|
95
|
+
|
96
|
+
# Nested exceptions
|
97
|
+
pirate.deep_clone include: :parrot, except: [ :name, { parrot: [ :name ] } ]
|
98
|
+
```
|
99
|
+
|
100
|
+
#### Inclusions
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
# Single attribute inclusion
|
104
|
+
pirate.deep_clone only: :name
|
105
|
+
|
106
|
+
# Multiple attribute inclusions
|
107
|
+
pirate.deep_clone only: [ :name, :nick_name ]
|
108
|
+
|
109
|
+
# Nested attribute inclusions
|
110
|
+
pirate.deep_clone include: :parrot, only: [ :name, { parrot: [ :name ] } ]
|
111
|
+
|
112
|
+
```
|
113
|
+
|
114
|
+
### Pre- and postprocessor
|
115
|
+
|
116
|
+
You can specify a pre- and/or a postprocessor to modify a duped object after duplication:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
pirate.deep_clone(include: :parrot, preprocessor: ->(original, kopy) { kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id) })
|
120
|
+
pirate.deep_clone(include: :parrot, postprocessor: ->(original, kopy) { kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id) })
|
121
|
+
```
|
122
|
+
|
123
|
+
_Note_: Specifying a postprocessor is essentially the same as specifying an optional block (see below).
|
124
|
+
|
125
|
+
_Note_: Using `deep_clone` with a processors will pass all associated objects that are being cloned to the processor, so be sure to check whether the object actually responds to your method of choice.
|
126
|
+
|
127
|
+
### Optional Block
|
128
|
+
|
129
|
+
Pass a block to `deep_clone` to modify a duped object after duplication:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
133
|
+
kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id)
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
_Note_: Using `deep_clone` with a block will also pass the associated objects that are being cloned to the block, so be sure to check whether the object actually responds to your method of choice.
|
138
|
+
|
139
|
+
### Cloning models with files
|
140
|
+
|
141
|
+
#### Carrierwave
|
142
|
+
|
143
|
+
If you are cloning models that have associated files through Carrierwave these will not get transferred automatically. To overcome the issue you need to explicitly set the file attribute.
|
144
|
+
|
145
|
+
Easiest solution is to add the code in a clone block as described above.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
149
|
+
kopy.thumbnail = original.thumbnail
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
#### ActiveStorage
|
154
|
+
|
155
|
+
For ActiveStorage, you have two options: you can either make a full copy, or share data blobs between two records.
|
156
|
+
|
157
|
+
##### Full copy example
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
# Rails 5.2, has_one_attached example 1
|
161
|
+
pirate.deep_clone include: [:parrot, :avatar_attachment, :avatar_blob]
|
162
|
+
|
163
|
+
# Rails 5.2, has_one_attached example 2
|
164
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
165
|
+
if kopy.is_a?(Pirate) && original.avatar.attached?
|
166
|
+
attachment = original.avatar
|
167
|
+
kopy.avatar.attach \
|
168
|
+
:io => StringIO.new(attachment.download),
|
169
|
+
:filename => attachment.filename,
|
170
|
+
:content_type => attachment.content_type
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Rails 5.2, has_many_attached example 1 (attach one by one)
|
175
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
176
|
+
if kopy.is_a?(Pirate) && original.crew_members_images.attached?
|
177
|
+
original.crew_members_images.each do |attachment|
|
178
|
+
kopy.crew_members_images.attach \
|
179
|
+
:io => StringIO.new(attachment.download),
|
180
|
+
:filename => attachment.filename,
|
181
|
+
:content_type => attachment.content_type
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Rails 5.2, has_many_attached example 2 (attach bulk)
|
187
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
188
|
+
if kopy.is_a?(Pirate) && original.crew_members_images.attached?
|
189
|
+
all_attachments_arr = original.crew_members_images.map do |attachment|
|
190
|
+
{
|
191
|
+
:io => StringIO.new(attachment.download),
|
192
|
+
:filename => attachment.filename,
|
193
|
+
:content_type => attachment.content_type
|
194
|
+
}
|
195
|
+
end
|
196
|
+
kopy.crew_members_images.attach(all_attachments_arr) # attach all at once
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Rails 6
|
201
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
202
|
+
if kopy.is_a?(Pirate) && original.avatar.attached?
|
203
|
+
original.avatar.open do |tempfile|
|
204
|
+
kopy.avatar.attach({
|
205
|
+
io: File.open(tempfile.path),
|
206
|
+
filename: original.avatar.blob.filename,
|
207
|
+
content_type: original.avatar.blob.content_type
|
208
|
+
})
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
##### Shallow copy example
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
pirate.deep_clone include: :parrot do |original, kopy|
|
218
|
+
kopy.avatar.attach(original.avatar.blob) if kopy.is_a?(Pirate) && original.avatar.attached?
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
### Skipping missing associations
|
223
|
+
|
224
|
+
By default, deep_cloneable will throw a `DeepCloneable::AssociationNotFoundException` error when an association cannot be found. You can also skip missing associations by specifying `skip_missing_associations` if needed, for example when you have associations on some (but not all) subclasses of an STI model:
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
pirate.deep_clone include: [:parrot, :rum], skip_missing_associations: true
|
228
|
+
```
|
229
|
+
|
230
|
+
### Note on Patches/Pull Requests
|
231
|
+
|
232
|
+
- Fork the project.
|
233
|
+
- Make your feature addition or bug fix.
|
234
|
+
- Add tests for it. This is important so I don't break it in a
|
235
|
+
future version unintentionally.
|
236
|
+
- Commit, do not mess with rakefile, version, or history.
|
237
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
238
|
+
- Send me a pull request. Bonus points for topic branches.
|
239
|
+
|
240
|
+
### Copyright
|
241
|
+
|
242
|
+
Copyright © 2024 Reinier de Lange. See LICENSE for details.
|
metadata
CHANGED
@@ -1,113 +1,79 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep_cloneable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 3.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Reinier de Lange
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2024-11-20 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
14
|
+
name: activerecord
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
22
|
-
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
19
|
+
version: 3.1.0
|
20
|
+
- - "<"
|
28
21
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: rails
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
22
|
+
version: '9'
|
38
23
|
type: :runtime
|
39
24
|
prerelease: false
|
40
25
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
26
|
requirements:
|
43
|
-
- -
|
27
|
+
- - ">="
|
44
28
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
46
|
-
-
|
47
|
-
name: jeweler
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - ! '>='
|
29
|
+
version: 3.1.0
|
30
|
+
- - "<"
|
60
31
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
62
|
-
description:
|
63
|
-
|
64
|
-
email:
|
32
|
+
version: '9'
|
33
|
+
description: Extends the functionality of ActiveRecord::Base#dup to perform a deep
|
34
|
+
clone that includes user specified associations.
|
35
|
+
email: rjdelange@icloud.com
|
65
36
|
executables: []
|
66
37
|
extensions: []
|
67
38
|
extra_rdoc_files:
|
68
39
|
- LICENSE
|
69
|
-
- README.rdoc
|
70
40
|
files:
|
71
|
-
-
|
41
|
+
- Appraisals
|
42
|
+
- CHANGELOG.md
|
72
43
|
- Gemfile
|
73
44
|
- Gemfile.lock
|
74
45
|
- LICENSE
|
75
|
-
- README.rdoc
|
76
46
|
- Rakefile
|
77
|
-
- VERSION
|
78
47
|
- deep_cloneable.gemspec
|
79
48
|
- init.rb
|
80
49
|
- lib/deep_cloneable.rb
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
84
|
-
-
|
85
|
-
|
86
|
-
|
87
|
-
|
50
|
+
- lib/deep_cloneable/association_not_found_exception.rb
|
51
|
+
- lib/deep_cloneable/deep_clone.rb
|
52
|
+
- lib/deep_cloneable/skip_validations.rb
|
53
|
+
- lib/deep_cloneable/version.rb
|
54
|
+
- readme.md
|
55
|
+
homepage: https://github.com/moiristo/deep_cloneable
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
88
60
|
rdoc_options: []
|
89
61
|
require_paths:
|
90
62
|
- lib
|
91
63
|
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
-
none: false
|
93
64
|
requirements:
|
94
|
-
- -
|
65
|
+
- - ">="
|
95
66
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
97
|
-
segments:
|
98
|
-
- 0
|
99
|
-
hash: -1579513982850858765
|
67
|
+
version: 1.9.3
|
100
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
-
none: false
|
102
69
|
requirements:
|
103
|
-
- -
|
70
|
+
- - ">="
|
104
71
|
- !ruby/object:Gem::Version
|
105
72
|
version: '0'
|
106
73
|
requirements: []
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
specification_version: 3
|
74
|
+
rubygems_version: 3.5.20
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
111
77
|
summary: This gem gives every ActiveRecord::Base object the possibility to do a deep
|
112
78
|
clone.
|
113
79
|
test_files: []
|
data/.document
DELETED
data/README.rdoc
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
= Deep_cloneable
|
2
|
-
|
3
|
-
This gem gives every ActiveRecord::Base object the possibility to do a deep clone. It is a rails3 upgrade of the deep_cloning plugin (http://github.com/openminds/deep_cloning).
|
4
|
-
|
5
|
-
== Requirements
|
6
|
-
|
7
|
-
* Activerecord 3.1, 3.2
|
8
|
-
|
9
|
-
* Rails 2.x/3.0 users, please check out the 'rails2.x-3.0' branch.
|
10
|
-
|
11
|
-
== Installation
|
12
|
-
|
13
|
-
* In your Gemfile:
|
14
|
-
|
15
|
-
gem 'deep_cloneable', '~> 1.3.1'
|
16
|
-
|
17
|
-
== Example
|
18
|
-
|
19
|
-
=== Cloning one single association
|
20
|
-
pirate.dup :include => :mateys
|
21
|
-
|
22
|
-
=== Cloning multiple associations
|
23
|
-
pirate.dup :include => [:mateys, :treasures]
|
24
|
-
|
25
|
-
=== Cloning really deep
|
26
|
-
pirate.dup :include => {:treasures => :gold_pieces}
|
27
|
-
|
28
|
-
=== Cloning really deep with multiple associations
|
29
|
-
pirate.dup :include => [:mateys, {:treasures => :gold_pieces}]
|
30
|
-
|
31
|
-
=== Cloning really deep with multiple associations and a dictionary
|
32
|
-
|
33
|
-
A dictionary ensures that models are not cloned multiple times when it is associated to nested models.
|
34
|
-
When using a dictionary, ensure recurring associations are cloned first:
|
35
|
-
|
36
|
-
pirate.dup :include => [:mateys, {:treasures => [:matey, :gold_pieces], :use_dictionary => true }]
|
37
|
-
|
38
|
-
If this is not an option for you, it is also possible to populate the dictionary manually in advance:
|
39
|
-
|
40
|
-
dict = { :mateys => {} }
|
41
|
-
pirate.mateys.each{|m| dict[:mateys][m] = m.dup }
|
42
|
-
pirate.dup :include => [:mateys, {:treasures => [:matey, :gold_pieces], :dictionary => dict }]
|
43
|
-
|
44
|
-
=== Cloning a model without an attribute
|
45
|
-
pirate.dup :except => :name
|
46
|
-
|
47
|
-
=== Cloning a model without multiple attributes
|
48
|
-
pirate.dup :except => [:name, :nick_name]
|
49
|
-
|
50
|
-
=== Cloning a model without an attribute or nested multiple attributes
|
51
|
-
pirate.dup :include => :parrot, :except => [:name, { :parrot => [:name] }]
|
52
|
-
|
53
|
-
=== Cloning with a block
|
54
|
-
pirate.dup :include => :parrot do |original, kopy|
|
55
|
-
kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id)
|
56
|
-
end
|
57
|
-
|
58
|
-
== Contributors
|
59
|
-
|
60
|
-
* Michael He
|
61
|
-
* Indrek Juhkam
|
62
|
-
* Mart Karu
|
63
|
-
* Rolf Timmermans
|
64
|
-
* Ilya Kuzmin
|
65
|
-
|
66
|
-
== Note on Patches/Pull Requests
|
67
|
-
|
68
|
-
* Fork the project.
|
69
|
-
* Make your feature addition or bug fix.
|
70
|
-
* Add tests for it. This is important so I don't break it in a
|
71
|
-
future version unintentionally.
|
72
|
-
* Commit, do not mess with rakefile, version, or history.
|
73
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
74
|
-
* Send me a pull request. Bonus points for topic branches.
|
75
|
-
|
76
|
-
== Copyright
|
77
|
-
|
78
|
-
Copyright (c) 2012 Reinier de Lange. See LICENSE for details.
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.4.0
|
data/test/database.yml
DELETED
data/test/schema.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
ActiveRecord::Schema.define(:version => 1) do
|
2
|
-
create_table :pirates, :force => true do |t|
|
3
|
-
t.column :name, :string
|
4
|
-
t.column :nick_name, :string, :default => 'no nickname'
|
5
|
-
t.column :age, :string
|
6
|
-
t.column :ship_id, :integer
|
7
|
-
t.column :ship_type, :string
|
8
|
-
end
|
9
|
-
|
10
|
-
create_table :parrots, :force => true do |t|
|
11
|
-
t.column :name, :string
|
12
|
-
t.column :pirate_id, :integer
|
13
|
-
end
|
14
|
-
|
15
|
-
create_table :mateys, :force => true do |t|
|
16
|
-
t.column :name, :string
|
17
|
-
t.column :pirate_id, :integer
|
18
|
-
end
|
19
|
-
|
20
|
-
create_table :treasures, :force => true do |t|
|
21
|
-
t.column :found_at, :string
|
22
|
-
t.column :owner, :integer
|
23
|
-
t.column :matey_id, :integer
|
24
|
-
end
|
25
|
-
|
26
|
-
create_table :gold_pieces, :force => true do |t|
|
27
|
-
t.column :treasure_id, :integer
|
28
|
-
end
|
29
|
-
|
30
|
-
create_table :battle_ships, :force => true do |t|
|
31
|
-
t.column :name, :string
|
32
|
-
end
|
33
|
-
|
34
|
-
create_table :pigs, :force => true do |t|
|
35
|
-
t.column :name, :string
|
36
|
-
t.column :human_id, :integer
|
37
|
-
end
|
38
|
-
|
39
|
-
create_table :humen, :force => true do |t|
|
40
|
-
t.column :name, :string
|
41
|
-
end
|
42
|
-
|
43
|
-
create_table :chickens, :force => true do |t|
|
44
|
-
t.column :name, :string
|
45
|
-
end
|
46
|
-
|
47
|
-
create_table :ownerships, :force => true do |t|
|
48
|
-
t.column :human_id, :integer
|
49
|
-
t.column :chicken_id, :integer
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
data/test/test_deep_cloneable.rb
DELETED
@@ -1,162 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/test_helper'
|
2
|
-
|
3
|
-
class TestDeepCloneable < Test::Unit::TestCase
|
4
|
-
load_schema
|
5
|
-
|
6
|
-
@@clone_method = ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR > 0 ? :dup : :clone
|
7
|
-
|
8
|
-
def setup
|
9
|
-
@jack = Pirate.create(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
|
10
|
-
@polly = Parrot.create(:name => 'Polly', :pirate => @jack)
|
11
|
-
@john = Matey.create(:name => 'John', :pirate => @jack)
|
12
|
-
@treasure = Treasure.create(:found_at => 'Isla del Muerte', :pirate => @jack, :matey => @john)
|
13
|
-
@gold_piece = GoldPiece.create(:treasure => @treasure)
|
14
|
-
@ship = BattleShip.create(:name => 'Black Pearl', :pirates => [@jack])
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_single_dup_exception
|
18
|
-
dup = @jack.send(@@clone_method, :except => :name)
|
19
|
-
assert dup.save
|
20
|
-
assert_equal @jack.name, @jack.send(@@clone_method).name # Old behaviour
|
21
|
-
assert_nil dup.name
|
22
|
-
assert_equal @jack.nick_name, dup.nick_name
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_multiple_dup_exception
|
26
|
-
dup = @jack.send(@@clone_method, :except => [:name, :nick_name])
|
27
|
-
assert dup.save
|
28
|
-
assert_nil dup.name
|
29
|
-
assert_equal 'no nickname', dup.nick_name
|
30
|
-
assert_equal @jack.age, dup.age
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_single_include_association
|
34
|
-
dup = @jack.send(@@clone_method, :include => :mateys)
|
35
|
-
assert dup.save
|
36
|
-
assert_equal 1, dup.mateys.size
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_single_include_belongs_to_polymorphic_association
|
40
|
-
dup = @jack.send(@@clone_method, :include => :ship)
|
41
|
-
assert dup.save
|
42
|
-
assert_not_nil dup.ship
|
43
|
-
assert_not_equal @jack.ship, dup.ship
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_single_include_has_many_polymorphic_association
|
47
|
-
dup = @ship.send(@@clone_method, :include => :pirates)
|
48
|
-
assert dup.save
|
49
|
-
assert dup.pirates.any?
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_multiple_include_association
|
53
|
-
dup = @jack.send(@@clone_method, :include => [:mateys, :treasures])
|
54
|
-
assert dup.save
|
55
|
-
assert_equal 1, dup.mateys.size
|
56
|
-
assert_equal 1, dup.treasures.size
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_deep_include_association
|
60
|
-
dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces})
|
61
|
-
assert dup.save
|
62
|
-
assert_equal 1, dup.treasures.size
|
63
|
-
assert_equal 1, dup.gold_pieces.size
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_include_association_assignments
|
67
|
-
dup = @jack.send(@@clone_method, :include => :treasures)
|
68
|
-
|
69
|
-
dup.treasures.each do |treasure|
|
70
|
-
assert_equal dup, treasure.pirate
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def test_multiple_and_deep_include_association
|
75
|
-
dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces, :mateys => {}})
|
76
|
-
assert dup.save
|
77
|
-
assert_equal 1, dup.treasures.size
|
78
|
-
assert_equal 1, dup.gold_pieces.size
|
79
|
-
assert_equal 1, dup.mateys.size
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_multiple_and_deep_include_association_with_array
|
83
|
-
dup = @jack.send(@@clone_method, :include => [{:treasures => :gold_pieces}, :mateys])
|
84
|
-
assert dup.save
|
85
|
-
assert_equal 1, dup.treasures.size
|
86
|
-
assert_equal 1, dup.gold_pieces.size
|
87
|
-
assert_equal 1, dup.mateys.size
|
88
|
-
end
|
89
|
-
|
90
|
-
def test_with_belongs_to_relation
|
91
|
-
dup = @jack.send(@@clone_method, :include => :parrot)
|
92
|
-
assert dup.save
|
93
|
-
assert_not_equal dup.parrot, @jack.parrot
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_should_pass_nested_exceptions
|
97
|
-
dup = @jack.send(@@clone_method, :include => :parrot, :except => [:name, { :parrot => [:name] }])
|
98
|
-
assert dup.save
|
99
|
-
assert_not_equal dup.parrot, @jack.parrot
|
100
|
-
assert_not_nil @jack.parrot.name
|
101
|
-
assert_nil dup.parrot.name
|
102
|
-
end
|
103
|
-
|
104
|
-
def test_should_not_double_dup_when_using_dictionary
|
105
|
-
current_matey_count = Matey.count
|
106
|
-
dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
|
107
|
-
dup.save!
|
108
|
-
|
109
|
-
assert_equal current_matey_count + 1, Matey.count
|
110
|
-
end
|
111
|
-
|
112
|
-
def test_should_not_double_dup_when_using_manual_dictionary
|
113
|
-
current_matey_count = Matey.count
|
114
|
-
|
115
|
-
dict = { :mateys => {} }
|
116
|
-
@jack.mateys.each{|m| dict[:mateys][m] = m.send(@@clone_method) }
|
117
|
-
|
118
|
-
dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :dictionary => dict)
|
119
|
-
dup.save!
|
120
|
-
|
121
|
-
assert_equal current_matey_count + 1, Matey.count
|
122
|
-
end
|
123
|
-
|
124
|
-
def test_should_support_ar_class_under_module
|
125
|
-
@human = Animal::Human.create :name => "Michael"
|
126
|
-
@pig = Animal::Pig.create :human => @human, :name => 'big pig'
|
127
|
-
|
128
|
-
dup_human = @human.send(@@clone_method, :include => [:pigs])
|
129
|
-
assert dup_human.save
|
130
|
-
assert_equal 1, dup_human.pigs.count
|
131
|
-
|
132
|
-
@human2 = Animal::Human.create :name => "John"
|
133
|
-
@pig2 = @human2.pigs.create :name => 'small pig'
|
134
|
-
|
135
|
-
dup_human_2 = @human.send(@@clone_method, :include => [:pigs])
|
136
|
-
assert dup_human_2.save
|
137
|
-
assert_equal 1, dup_human_2.pigs.count
|
138
|
-
end
|
139
|
-
|
140
|
-
def test_should_dup_many_to_many_associations
|
141
|
-
@human = Animal::Human.create :name => "Michael"
|
142
|
-
@human2 = Animal::Human.create :name => "Jack"
|
143
|
-
@chicken1 = Animal::Chicken.create :name => 'Chick1'
|
144
|
-
@chicken2 = Animal::Chicken.create :name => 'Chick2'
|
145
|
-
@human.chickens << [@chicken1, @chicken2]
|
146
|
-
@human2.chickens << [@chicken1, @chicken2]
|
147
|
-
|
148
|
-
dup_human = @human.send(@@clone_method, :include => :ownerships)
|
149
|
-
assert dup_human.save
|
150
|
-
assert_equal 2, dup_human.chickens.count
|
151
|
-
end
|
152
|
-
|
153
|
-
def test_should_dup_with_block
|
154
|
-
dup = @jack.send(@@clone_method, :include => :parrot) do |original, kopy|
|
155
|
-
kopy.cloned_from_id = original.id
|
156
|
-
end
|
157
|
-
|
158
|
-
assert dup.save
|
159
|
-
assert_equal @jack.id, dup.cloned_from_id
|
160
|
-
assert_equal @jack.parrot.id, dup.parrot.cloned_from_id
|
161
|
-
end
|
162
|
-
end
|