amoeba 1.2.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.cane +4 -0
- data/.gitignore +4 -1
- data/.rspec +2 -0
- data/.rubocop.yml +17 -0
- data/.travis.yml +110 -0
- data/Appraisals +76 -0
- data/Gemfile +11 -3
- data/README.md +763 -529
- data/Rakefile +6 -1
- data/amoeba.gemspec +20 -15
- data/defaults.reek +11 -0
- data/gemfiles/activerecord_4.2.gemfile +18 -0
- data/gemfiles/activerecord_5.0.gemfile +18 -0
- data/gemfiles/activerecord_5.1.gemfile +18 -0
- data/gemfiles/activerecord_5.2.gemfile +18 -0
- data/gemfiles/activerecord_6.0.gemfile +18 -0
- data/gemfiles/activerecord_6.1.gemfile +18 -0
- data/gemfiles/activerecord_head.gemfile +24 -0
- data/gemfiles/jruby_activerecord_6.1.gemfile +19 -0
- data/gemfiles/jruby_activerecord_head.gemfile +28 -0
- data/lib/amoeba.rb +13 -517
- data/lib/amoeba/class_methods.rb +28 -0
- data/lib/amoeba/cloner.rb +172 -0
- data/lib/amoeba/config.rb +182 -0
- data/lib/amoeba/instance_methods.rb +37 -0
- data/lib/amoeba/macros.rb +14 -0
- data/lib/amoeba/macros/base.rb +26 -0
- data/lib/amoeba/macros/has_and_belongs_to_many.rb +19 -0
- data/lib/amoeba/macros/has_many.rb +42 -0
- data/lib/amoeba/macros/has_one.rb +15 -0
- data/lib/amoeba/version.rb +1 -1
- data/spec/lib/amoeba_spec.rb +336 -111
- data/spec/spec_helper.rb +24 -3
- data/spec/support/data.rb +65 -84
- data/spec/support/models.rb +241 -25
- data/spec/support/schema.rb +102 -41
- metadata +63 -70
- data/.rvmrc +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4ae461133565a412e2338cfa8b4f2fd8cbed8fa5a4b5bd56724c8f583888312c
|
4
|
+
data.tar.gz: 127513d887e21e276b1511c0b6556d311832df82d781f9bd46bac708d4a830d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c5e8515376b4a6cb533630fb17980bc72ba46b916e40a8bd66e99944e31dd5603d63a5a33d4fc5aeed09ea59e4750f94a8a70ded31c2d0b596c82ca290603947
|
7
|
+
data.tar.gz: dd2e5f454c30535c68a704b1488a8de0e33bfe237130a79a57584cd5ae4bb1437ba99fef0f5e1dd1784750d64a9a8ac753c1064d35cdb4ea8a635dcdfbafec0c
|
data/.cane
ADDED
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
AllCops:
|
2
|
+
Include:
|
3
|
+
- '**/Rakefile'
|
4
|
+
Exclude:
|
5
|
+
- 'spec/**/*'
|
6
|
+
Metrics/LineLength:
|
7
|
+
Max: 99
|
8
|
+
Style/FileName:
|
9
|
+
Enabled: false
|
10
|
+
Style/ModuleFunction:
|
11
|
+
Enabled: false
|
12
|
+
Style/Encoding:
|
13
|
+
Enabled: false
|
14
|
+
Documentation:
|
15
|
+
Enabled: false
|
16
|
+
Metrics/MethodLength:
|
17
|
+
Max: 15
|
data/.travis.yml
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2
|
4
|
+
- 2.3
|
5
|
+
- 2.4
|
6
|
+
- 2.5
|
7
|
+
- 2.6
|
8
|
+
- 2.7
|
9
|
+
- 3.0
|
10
|
+
- ruby-head
|
11
|
+
- jruby
|
12
|
+
gemfile:
|
13
|
+
- gemfiles/activerecord_4.2.gemfile
|
14
|
+
- gemfiles/activerecord_5.0.gemfile
|
15
|
+
- gemfiles/activerecord_5.1.gemfile
|
16
|
+
- gemfiles/activerecord_5.2.gemfile
|
17
|
+
- gemfiles/activerecord_6.0.gemfile
|
18
|
+
- gemfiles/activerecord_6.1.gemfile
|
19
|
+
- gemfiles/jruby_activerecord_6.1.gemfile
|
20
|
+
- gemfiles/activerecord_head.gemfile
|
21
|
+
- gemfiles/jruby_activerecord_head.gemfile
|
22
|
+
matrix:
|
23
|
+
allow_failures:
|
24
|
+
- rvm: ruby-head
|
25
|
+
- rvm: jruby
|
26
|
+
# These may work if there is a new version of sqlite3 1.3.x supporting
|
27
|
+
# Ruby 3.0
|
28
|
+
- rvm: 3.0
|
29
|
+
gemfile: gemfiles/activerecord_5.0.gemfile
|
30
|
+
- rvm: 3.0
|
31
|
+
gemfile: gemfiles/activerecord_5.1.gemfile
|
32
|
+
- rvm: 3.0
|
33
|
+
gemfile: gemfiles/activerecord_5.2.gemfile
|
34
|
+
exclude:
|
35
|
+
- rvm: 2.2
|
36
|
+
gemfile: gemfiles/activerecord_6.0.gemfile
|
37
|
+
- rvm: 2.2
|
38
|
+
gemfile: gemfiles/activerecord_6.1.gemfile
|
39
|
+
- rvm: 2.2
|
40
|
+
gemfile: gemfiles/activerecord_head.gemfile
|
41
|
+
- rvm: 2.2
|
42
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
43
|
+
- rvm: 2.2
|
44
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
45
|
+
- rvm: 2.3
|
46
|
+
gemfile: gemfiles/activerecord_6.0.gemfile
|
47
|
+
- rvm: 2.3
|
48
|
+
gemfile: gemfiles/activerecord_6.1.gemfile
|
49
|
+
- rvm: 2.3
|
50
|
+
gemfile: gemfiles/activerecord_head.gemfile
|
51
|
+
- rvm: 2.3
|
52
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
53
|
+
- rvm: 2.3
|
54
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
55
|
+
- rvm: 2.4
|
56
|
+
gemfile: gemfiles/activerecord_6.0.gemfile
|
57
|
+
- rvm: 2.4
|
58
|
+
gemfile: gemfiles/activerecord_6.1.gemfile
|
59
|
+
- rvm: 2.4
|
60
|
+
gemfile: gemfiles/activerecord_head.gemfile
|
61
|
+
- rvm: 2.4
|
62
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
63
|
+
- rvm: 2.4
|
64
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
65
|
+
- rvm: 2.5
|
66
|
+
gemfile: gemfiles/activerecord_head.gemfile
|
67
|
+
- rvm: 2.5
|
68
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
69
|
+
- rvm: 2.5
|
70
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
71
|
+
- rvm: 2.6
|
72
|
+
gemfile: gemfiles/activerecord_head.gemfile
|
73
|
+
- rvm: 2.6
|
74
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
75
|
+
- rvm: 2.6
|
76
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
77
|
+
- rvm: 2.7
|
78
|
+
gemfile: gemfiles/activerecord_4.2.gemfile
|
79
|
+
- rvm: 2.7
|
80
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
81
|
+
- rvm: 2.7
|
82
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
83
|
+
- rvm: 3.0
|
84
|
+
gemfile: gemfiles/activerecord_4.2.gemfile
|
85
|
+
- rvm: 3.0
|
86
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
87
|
+
- rvm: 3.0
|
88
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
89
|
+
- rvm: ruby-head
|
90
|
+
gemfile: gemfiles/activerecord_4.2.gemfile
|
91
|
+
- rvm: ruby-head
|
92
|
+
gemfile: gemfiles/jruby_activerecord_6.1.gemfile
|
93
|
+
- rvm: ruby-head
|
94
|
+
gemfile: gemfiles/jruby_activerecord_head.gemfile
|
95
|
+
- rvm: jruby
|
96
|
+
gemfile: gemfiles/activerecord_4.2.gemfile
|
97
|
+
- rvm: jruby
|
98
|
+
gemfile: gemfiles/activerecord_5.0.gemfile
|
99
|
+
- rvm: jruby
|
100
|
+
gemfile: gemfiles/activerecord_5.1.gemfile
|
101
|
+
- rvm: jruby
|
102
|
+
gemfile: gemfiles/activerecord_5.2.gemfile
|
103
|
+
- rvm: jruby
|
104
|
+
gemfile: gemfiles/activerecord_6.0.gemfile
|
105
|
+
- rvm: jruby
|
106
|
+
gemfile: gemfiles/activerecord_6.1.gemfile
|
107
|
+
- rvm: jruby
|
108
|
+
gemfile: gemfiles/activerecord_head.gemfile
|
109
|
+
bundler_args: --without local_development
|
110
|
+
before_install: gem install bundler -v 1.17.3
|
data/Appraisals
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
appraise 'activerecord-4.2' do
|
2
|
+
gem 'activerecord', '~> 4.2.0'
|
3
|
+
group :development, :test do
|
4
|
+
gem "sqlite3", "~> 1.3.0"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
appraise 'activerecord-5.0' do
|
9
|
+
gem 'activerecord', '~> 5.0.0'
|
10
|
+
group :development, :test do
|
11
|
+
gem "sqlite3", "~> 1.3.0"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
appraise 'activerecord-5.1' do
|
16
|
+
gem 'activerecord', '~> 5.1.0'
|
17
|
+
group :development, :test do
|
18
|
+
gem "sqlite3", "~> 1.3.0"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
appraise 'activerecord-5.2' do
|
23
|
+
gem 'activerecord', '~> 5.2.0'
|
24
|
+
group :development, :test do
|
25
|
+
gem "sqlite3", "~> 1.3.0"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
appraise 'activerecord-6.0' do
|
30
|
+
gem 'activerecord', '~> 6.0.0'
|
31
|
+
group :development, :test do
|
32
|
+
gem "sqlite3", "~> 1.4.0"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
appraise 'activerecord-6.1' do
|
37
|
+
gem 'activerecord', '~> 6.1.0'
|
38
|
+
group :development, :test do
|
39
|
+
gem "sqlite3", "~> 1.4.0"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
appraise 'jruby-activerecord-6.1' do
|
44
|
+
gem 'activerecord', '~> 6.1.0'
|
45
|
+
group :development, :test do
|
46
|
+
gem 'activerecord-jdbc-adapter', '~> 61.0'
|
47
|
+
gem 'activerecord-jdbcsqlite3-adapter', '~> 61.0'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
appraise 'activerecord-head' do
|
52
|
+
git 'git://github.com/rails/arel.git' do
|
53
|
+
gem 'arel'
|
54
|
+
end
|
55
|
+
git 'git://github.com/rails/rails.git', branch: 'main' do
|
56
|
+
gem 'activerecord'
|
57
|
+
end
|
58
|
+
group :development, :test do
|
59
|
+
gem "sqlite3", "~> 1.4.0"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
appraise 'jruby-activerecord-head' do
|
64
|
+
git 'git://github.com/rails/arel.git' do
|
65
|
+
gem 'arel'
|
66
|
+
end
|
67
|
+
git 'git://github.com/rails/rails.git', branch: 'main' do
|
68
|
+
gem 'activerecord'
|
69
|
+
end
|
70
|
+
group :development, :test do
|
71
|
+
git 'git://github.com/jruby/activerecord-jdbc-adapter' do
|
72
|
+
gem 'activerecord-jdbc-adapter'
|
73
|
+
gem 'activerecord-jdbcsqlite3-adapter', glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/Gemfile
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
source
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in power_dup.gemspec
|
1
|
+
source 'https://rubygems.org'
|
4
2
|
gemspec
|
3
|
+
|
4
|
+
group :development, :test do
|
5
|
+
gem 'rake'
|
6
|
+
gem 'coveralls', require: false
|
7
|
+
end
|
8
|
+
|
9
|
+
group :local_development do
|
10
|
+
gem 'pry'
|
11
|
+
gem 'appraisal'
|
12
|
+
end
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# Amoeba
|
2
2
|
|
3
|
-
Easy
|
3
|
+
Easy cloning of active_record objects including associations and several operations under associations and attributes.
|
4
4
|
|
5
|
-
![
|
5
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/d4809ae57ca999fff022/maintainability)](https://codeclimate.com/github/amoeba-rb/amoeba/maintainability)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/amoeba.svg)](http://badge.fury.io/rb/amoeba)
|
7
|
+
[![Build Status](https://travis-ci.org/amoeba-rb/amoeba.svg?branch=master)](https://travis-ci.org/amoeba-rb/amoeba)
|
6
8
|
|
7
9
|
## What?
|
8
10
|
|
@@ -12,9 +14,9 @@ This gem is named "Amoeba" because amoebas are (small life forms that are) good
|
|
12
14
|
|
13
15
|
### Technical Details
|
14
16
|
|
15
|
-
An ActiveRecord extension gem to allow the duplication of associated child record objects when duplicating an active record model.
|
17
|
+
An ActiveRecord extension gem to allow the duplication of associated child record objects when duplicating an active record model.
|
16
18
|
|
17
|
-
Rails
|
19
|
+
Rails 4.x, 5.0, 5.1, 5.2, 6.0, 6.1 compatible.
|
18
20
|
|
19
21
|
### Features
|
20
22
|
|
@@ -44,26 +46,32 @@ Rails 3.2 compatible.
|
|
44
46
|
|
45
47
|
is hopefully as you would expect:
|
46
48
|
|
47
|
-
|
49
|
+
```sh
|
50
|
+
gem install amoeba
|
51
|
+
```
|
48
52
|
|
49
53
|
or just add it to your Gemfile:
|
50
54
|
|
51
|
-
|
55
|
+
```sh
|
56
|
+
gem 'amoeba'
|
57
|
+
```
|
52
58
|
|
53
|
-
Configure your models with one of the styles below and then just run the `
|
59
|
+
Configure your models with one of the styles below and then just run the `amoeba_dup` method on your model where you would run the `dup` method normally:
|
54
60
|
|
55
|
-
|
56
|
-
|
57
|
-
|
61
|
+
```ruby
|
62
|
+
p = Post.create(:title => "Hello World!", :content => "Lorum ipsum dolor")
|
63
|
+
p.comments.create(:content => "I love it!")
|
64
|
+
p.comments.create(:content => "This sucks!")
|
58
65
|
|
59
|
-
|
66
|
+
puts Comment.all.count # should be 2
|
60
67
|
|
61
|
-
|
62
|
-
|
68
|
+
my_copy = p.amoeba_dup
|
69
|
+
my_copy.save
|
63
70
|
|
64
|
-
|
71
|
+
puts Comment.all.count # should be 4
|
72
|
+
```
|
65
73
|
|
66
|
-
By default, when enabled, amoeba will copy any and all associated child records automatically and
|
74
|
+
By default, when enabled, amoeba will copy any and all associated child records automatically and associate them with the new parent record.
|
67
75
|
|
68
76
|
You can configure the behavior to only include fields that you list or to only include fields that you don't exclude. Of the three, the most performant will be the indiscriminate style, followed by the inclusive style, and the exclusive style will be the slowest because of the need for an extra explicit check on each field. This performance difference is likely negligible enough that you can choose the style to use based on which is easiest to read and write, however, if your data tree is large enough and you need control over what fields get copied, inclusive style is probably a better choice than exclusive style.
|
69
77
|
|
@@ -77,144 +85,197 @@ This is the most basic usage case and will simply enable the copying of any know
|
|
77
85
|
|
78
86
|
If you have some models for a blog about like this:
|
79
87
|
|
80
|
-
|
81
|
-
|
82
|
-
|
88
|
+
```ruby
|
89
|
+
class Post < ActiveRecord::Base
|
90
|
+
has_many :comments
|
91
|
+
end
|
83
92
|
|
84
|
-
|
85
|
-
|
86
|
-
|
93
|
+
class Comment < ActiveRecord::Base
|
94
|
+
belongs_to :post
|
95
|
+
end
|
96
|
+
```
|
87
97
|
|
88
98
|
simply add the amoeba configuration block to your model and call the enable method to enable the copying of child records, like this:
|
89
99
|
|
90
|
-
|
91
|
-
|
100
|
+
```ruby
|
101
|
+
class Post < ActiveRecord::Base
|
102
|
+
has_many :comments
|
92
103
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
104
|
+
amoeba do
|
105
|
+
enable
|
106
|
+
end
|
107
|
+
end
|
97
108
|
|
98
|
-
|
99
|
-
|
100
|
-
|
109
|
+
class Comment < ActiveRecord::Base
|
110
|
+
belongs_to :post
|
111
|
+
end
|
112
|
+
```
|
101
113
|
|
102
|
-
Child records will be automatically copied when you run the
|
114
|
+
Child records will be automatically copied when you run the `amoeba_dup` method.
|
103
115
|
|
104
116
|
#### Inclusive Style
|
105
117
|
|
106
118
|
If you only want some of the associations copied but not others, you may use the inclusive style:
|
107
119
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
120
|
+
```ruby
|
121
|
+
class Post < ActiveRecord::Base
|
122
|
+
has_many :comments
|
123
|
+
has_many :tags
|
124
|
+
has_many :authors
|
112
125
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
126
|
+
amoeba do
|
127
|
+
enable
|
128
|
+
include_association :tags
|
129
|
+
include_association :authors
|
130
|
+
end
|
131
|
+
end
|
119
132
|
|
120
|
-
|
121
|
-
|
122
|
-
|
133
|
+
class Comment < ActiveRecord::Base
|
134
|
+
belongs_to :post
|
135
|
+
end
|
136
|
+
```
|
123
137
|
|
124
138
|
Using the inclusive style within the amoeba block actually implies that you wish to enable amoeba, so there is no need to run the enable method, though it won't hurt either:
|
125
139
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
140
|
+
```ruby
|
141
|
+
class Post < ActiveRecord::Base
|
142
|
+
has_many :comments
|
143
|
+
has_many :tags
|
144
|
+
has_many :authors
|
145
|
+
|
146
|
+
amoeba do
|
147
|
+
include_association :tags
|
148
|
+
include_association :authors
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Comment < ActiveRecord::Base
|
153
|
+
belongs_to :post
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
You may also specify fields to be copied by passing an array. If you call the `include_association` with a single value, it will be appended to the list of already included fields. If you pass an array, your array will overwrite the original values.
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
class Post < ActiveRecord::Base
|
161
|
+
has_many :comments
|
162
|
+
has_many :tags
|
163
|
+
has_many :authors
|
164
|
+
|
165
|
+
amoeba do
|
166
|
+
include_association [:tags, :authors]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Comment < ActiveRecord::Base
|
171
|
+
belongs_to :post
|
172
|
+
end
|
173
|
+
```
|
156
174
|
|
157
175
|
These examples will copy the post's tags and authors but not its comments.
|
158
176
|
|
159
|
-
The inclusive style, when used, will automatically disable any
|
177
|
+
The inclusive style, when used, will automatically disable any other style that was previously selected.
|
160
178
|
|
161
179
|
#### Exclusive Style
|
162
180
|
|
163
181
|
If you have more fields to include than to exclude, you may wish to shorten the amount of typing and reading you need to do by using the exclusive style. All fields that are not explicitly excluded will be copied:
|
164
182
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
183
|
+
```ruby
|
184
|
+
class Post < ActiveRecord::Base
|
185
|
+
has_many :comments
|
186
|
+
has_many :tags
|
187
|
+
has_many :authors
|
169
188
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
189
|
+
amoeba do
|
190
|
+
exclude_association :comments
|
191
|
+
end
|
192
|
+
end
|
174
193
|
|
175
|
-
|
176
|
-
|
177
|
-
|
194
|
+
class Comment < ActiveRecord::Base
|
195
|
+
belongs_to :post
|
196
|
+
end
|
197
|
+
```
|
178
198
|
|
179
199
|
This example does the same thing as the inclusive style example, it will copy the post's tags and authors but not its comments. As with inclusive style, there is no need to explicitly enable amoeba when specifying fields to exclude.
|
180
200
|
|
181
|
-
The exclusive style, when used, will automatically disable any other style that was previously selected, so if you selected include fields, and then you choose some exclude fields, the `
|
201
|
+
The exclusive style, when used, will automatically disable any other style that was previously selected, so if you selected include fields, and then you choose some exclude fields, the `exclude_association` method will disable the previously selected inclusive style and wipe out any corresponding include fields.
|
202
|
+
|
203
|
+
#### Conditions
|
204
|
+
|
205
|
+
Also if you need to path extra condition for include or exclude relationship you can path method name to `:if` option.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
class Post < ActiveRecord::Base
|
209
|
+
has_many :comments
|
210
|
+
has_many :tags
|
211
|
+
|
212
|
+
amoeba do
|
213
|
+
include_association :comments, if: :popular?
|
214
|
+
end
|
215
|
+
|
216
|
+
def popular?
|
217
|
+
likes > 15
|
218
|
+
end
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
After call `Post.first.amoeba_dup` if `likes` is larger 15 than all comments will be duplicated too, but in another situation - no relations will be cloned. Same behavior will be for `exclude_association`.
|
223
|
+
|
224
|
+
**Be aware**! If you wrote:
|
225
|
+
```ruby
|
226
|
+
class Post < ActiveRecord::Base
|
227
|
+
has_many :comments
|
228
|
+
has_many :tags
|
229
|
+
|
230
|
+
amoeba do
|
231
|
+
exclude_association :tags
|
232
|
+
include_association :comments, if: :popular?
|
233
|
+
end
|
234
|
+
|
235
|
+
def popular?
|
236
|
+
likes > 15
|
237
|
+
end
|
238
|
+
end
|
239
|
+
```
|
240
|
+
inclusion strategy will be chosen regardless of the result of `popular?` method call (the same for reverse situation).
|
182
241
|
|
183
242
|
#### Cloning
|
184
243
|
|
185
244
|
If you are using a Many-to-Many relationship, you may tell amoeba to actually make duplicates of the original related records rather than merely maintaining association with the original records. Cloning is easy, merely tell amoeba which fields to clone in the same way you tell it which fields to include or exclude.
|
186
245
|
|
187
|
-
|
188
|
-
|
246
|
+
```ruby
|
247
|
+
class Post < ActiveRecord::Base
|
248
|
+
has_and_belongs_to_many :warnings
|
189
249
|
|
190
|
-
|
191
|
-
|
250
|
+
has_many :post_widgets
|
251
|
+
has_many :widgets, :through => :post_widgets
|
192
252
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
253
|
+
amoeba do
|
254
|
+
enable
|
255
|
+
clone [:widgets, :warnings]
|
256
|
+
end
|
257
|
+
end
|
198
258
|
|
199
|
-
|
200
|
-
|
201
|
-
|
259
|
+
class Warning < ActiveRecord::Base
|
260
|
+
has_and_belongs_to_many :posts
|
261
|
+
end
|
202
262
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
263
|
+
class PostWidget < ActiveRecord::Base
|
264
|
+
belongs_to :widget
|
265
|
+
belongs_to :post
|
266
|
+
end
|
207
267
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
268
|
+
class Widget < ActiveRecord::Base
|
269
|
+
has_many :post_widgets
|
270
|
+
has_many :posts, :through => :post_widgets
|
271
|
+
end
|
272
|
+
```
|
212
273
|
|
213
274
|
This example will actually duplicate the warnings and widgets in the database. If there were originally 3 warnings in the database then, upon duplicating a post, you will end up with 6 warnings in the database. This is in contrast to the default behavior where your new post would merely be re-associated with any previously existing warnings and those warnings themselves would not be duplicated.
|
214
275
|
|
215
|
-
|
276
|
+
#### Limiting Association Types
|
216
277
|
|
217
|
-
By default, amoeba recognizes and
|
278
|
+
By default, amoeba recognizes and attempts to copy any children of the following association types:
|
218
279
|
|
219
280
|
- has one
|
220
281
|
- has many
|
@@ -222,134 +283,54 @@ By default, amoeba recognizes and attemps to copy any children of the following
|
|
222
283
|
|
223
284
|
You may control which association types amoeba applies itself to by using the `recognize` method within the amoeba configuration block.
|
224
285
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
286
|
+
```ruby
|
287
|
+
class Post < ActiveRecord::Base
|
288
|
+
has_one :config
|
289
|
+
has_many :comments
|
290
|
+
has_and_belongs_to_many :tags
|
229
291
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
292
|
+
amoeba do
|
293
|
+
recognize [:has_one, :has_and_belongs_to_many]
|
294
|
+
end
|
295
|
+
end
|
234
296
|
|
235
|
-
|
236
|
-
|
237
|
-
|
297
|
+
class Comment < ActiveRecord::Base
|
298
|
+
belongs_to :post
|
299
|
+
end
|
238
300
|
|
239
|
-
|
240
|
-
|
241
|
-
|
301
|
+
class Tag < ActiveRecord::Base
|
302
|
+
has_and_belongs_to_many :posts
|
303
|
+
end
|
304
|
+
```
|
242
305
|
|
243
306
|
This example will copy the post's configuration data and keep tags associated with the new post, but will not copy the post's comments because amoeba will only recognize and copy children of `has_one` and `has_and_belongs_to_many` associations and in this example, comments are not an `has_and_belongs_to_many` association.
|
244
307
|
|
245
|
-
### Nested Association Validation
|
246
|
-
|
247
|
-
If you end up with some validation issues when trying to validate the presence of a child's `belongs_to` association, just be sure to include the `:inverse_of` declaration on your relationships and all should be well.
|
248
|
-
|
249
|
-
For example this will throw a validation error saying that your posts are invalid:
|
250
|
-
|
251
|
-
class Author < ActiveRecord::Base
|
252
|
-
has_many :posts
|
253
|
-
|
254
|
-
amoeba do
|
255
|
-
enable
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
class Post < ActiveRecord::Base
|
260
|
-
belongs_to :author
|
261
|
-
validates_presence_of :author
|
262
|
-
|
263
|
-
amoeba do
|
264
|
-
enable
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
author = Author.find(1)
|
269
|
-
author.dup
|
270
|
-
|
271
|
-
author.save # this will fail validation
|
272
|
-
|
273
|
-
Wheras this will work fine:
|
274
|
-
|
275
|
-
class Author < ActiveRecord::Base
|
276
|
-
has_many :posts, :inverse_of => :author
|
277
|
-
|
278
|
-
amoeba do
|
279
|
-
enable
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
class Post < ActiveRecord::Base
|
284
|
-
belongs_to :author, :inverse_of => :posts
|
285
|
-
validates_presence_of :author
|
286
|
-
|
287
|
-
amoeba do
|
288
|
-
enable
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
author = Author.find(1)
|
293
|
-
author.dup
|
294
|
-
|
295
|
-
author.save # this will pass validation
|
296
|
-
|
297
|
-
This issue is not amoeba specific and also occurs when creating new objects using `accepts_nested_attributes_for`, like this:
|
298
|
-
|
299
|
-
class Author < ActiveRecord::Base
|
300
|
-
has_many :posts
|
301
|
-
accepts_nested_attributes_for :posts
|
302
|
-
end
|
303
|
-
|
304
|
-
class Post < ActiveRecord::Base
|
305
|
-
belongs_to :author
|
306
|
-
validates_presence_of :author
|
307
|
-
end
|
308
|
-
|
309
|
-
# this will fail validation
|
310
|
-
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
311
|
-
|
312
|
-
This issue with `accepts_nested_attributes_for` can also be solved by using `:inverse_of`, like this:
|
313
|
-
|
314
|
-
class Author < ActiveRecord::Base
|
315
|
-
has_many :posts, :inverse_of => :author
|
316
|
-
accepts_nested_attributes_for :posts
|
317
|
-
end
|
318
|
-
|
319
|
-
class Post < ActiveRecord::Base
|
320
|
-
belongs_to :author, :inverse_of => :posts
|
321
|
-
validates_presence_of :author
|
322
|
-
end
|
323
|
-
|
324
|
-
# this will pass validation
|
325
|
-
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
326
|
-
|
327
|
-
The crux of the issue is that upon duplication, the new `Author` instance does not yet have an ID because it has not yet been persisted, so the `:posts` do not yet have an `:author_id` either, and thus no `:author` and thus they will fail validation. This issue may likely affect amoeba usage so if you get some validation failures, be sure to add `:inverse_of` to your models.
|
328
|
-
|
329
308
|
### Field Preprocessors
|
330
309
|
|
331
310
|
#### Nullify
|
332
311
|
|
333
312
|
If you wish to prevent a regular (non `has_*` association based) field from retaining it's value when copied, you may "zero out" or "nullify" the field, like this:
|
334
313
|
|
335
|
-
|
336
|
-
|
337
|
-
|
314
|
+
```ruby
|
315
|
+
class Topic < ActiveRecord::Base
|
316
|
+
has_many :posts
|
317
|
+
end
|
338
318
|
|
339
|
-
|
340
|
-
|
341
|
-
|
319
|
+
class Post < ActiveRecord::Base
|
320
|
+
belongs_to :topic
|
321
|
+
has_many :comments
|
342
322
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
323
|
+
amoeba do
|
324
|
+
enable
|
325
|
+
nullify :date_published
|
326
|
+
nullify :topic_id
|
327
|
+
end
|
328
|
+
end
|
349
329
|
|
350
|
-
|
351
|
-
|
352
|
-
|
330
|
+
class Comment < ActiveRecord::Base
|
331
|
+
belongs_to :post
|
332
|
+
end
|
333
|
+
```
|
353
334
|
|
354
335
|
This example will copy all of a post's comments. It will also nullify the publishing date and dissociate the post from its original topic.
|
355
336
|
|
@@ -357,13 +338,15 @@ Unlike inclusive and exclusive styles, specifying null fields will not automatic
|
|
357
338
|
|
358
339
|
#### Set
|
359
340
|
|
360
|
-
If you wish to just set a field to an
|
341
|
+
If you wish to just set a field to an arbitrary value on all duplicated objects you may use the `set` directive. For example, if you wanted to copy an object that has some kind of approval process associated with it, you likely may wish to set the new object's state to be open or "in progress" again.
|
361
342
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
343
|
+
```ruby
|
344
|
+
class Post < ActiveRecord::Base
|
345
|
+
amoeba do
|
346
|
+
set :state_tracker => "open_for_editing"
|
347
|
+
end
|
348
|
+
end
|
349
|
+
```
|
367
350
|
|
368
351
|
In this example, when a post is duplicated, it's `state_tracker` field will always be given a value of `open_for_editing` to start.
|
369
352
|
|
@@ -371,34 +354,40 @@ In this example, when a post is duplicated, it's `state_tracker` field will alwa
|
|
371
354
|
|
372
355
|
You may add a string to the beginning of a copied object's field during the copy phase:
|
373
356
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
357
|
+
```ruby
|
358
|
+
class Post < ActiveRecord::Base
|
359
|
+
amoeba do
|
360
|
+
enable
|
361
|
+
prepend :title => "Copy of "
|
362
|
+
end
|
363
|
+
end
|
364
|
+
```
|
380
365
|
|
381
366
|
#### Append
|
382
367
|
|
383
368
|
You may add a string to the end of a copied object's field during the copy phase:
|
384
369
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
370
|
+
```ruby
|
371
|
+
class Post < ActiveRecord::Base
|
372
|
+
amoeba do
|
373
|
+
enable
|
374
|
+
append :title => "Copy of "
|
375
|
+
end
|
376
|
+
end
|
377
|
+
```
|
391
378
|
|
392
379
|
#### Regex
|
393
380
|
|
394
381
|
You may run a search and replace query on a copied object's field during the copy phase:
|
395
382
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
383
|
+
```ruby
|
384
|
+
class Post < ActiveRecord::Base
|
385
|
+
amoeba do
|
386
|
+
enable
|
387
|
+
regex :contents => {:replace => /dog/, :with => 'cat'}
|
388
|
+
end
|
389
|
+
end
|
390
|
+
```
|
402
391
|
|
403
392
|
#### Custom Methods
|
404
393
|
|
@@ -406,133 +395,147 @@ You may run a search and replace query on a copied object's field during the cop
|
|
406
395
|
|
407
396
|
You may run a custom method or methods to do basically anything you like, simply pass a lambda block, or an array of lambda blocks to the `customize` directive. Each block must have the same form, meaning that each block must accept two parameters, the original object and the newly copied object. You may then do whatever you wish, like this:
|
408
397
|
|
409
|
-
|
410
|
-
|
411
|
-
|
398
|
+
```ruby
|
399
|
+
class Post < ActiveRecord::Base
|
400
|
+
amoeba do
|
401
|
+
prepend :title => "Hello world! "
|
412
402
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
end
|
417
|
-
})
|
418
|
-
|
419
|
-
append :comments => "... know what I'm sayin?"
|
403
|
+
customize(lambda { |original_post,new_post|
|
404
|
+
if original_post.foo == "bar"
|
405
|
+
new_post.baz = "qux"
|
420
406
|
end
|
421
|
-
|
407
|
+
})
|
408
|
+
|
409
|
+
append :comments => "... know what I'm sayin?"
|
410
|
+
end
|
411
|
+
end
|
412
|
+
```
|
422
413
|
|
423
414
|
or this, using an array:
|
424
415
|
|
425
|
-
|
426
|
-
|
416
|
+
```ruby
|
417
|
+
class Post < ActiveRecord::Base
|
418
|
+
has_and_belongs_to_many :tags
|
427
419
|
|
428
|
-
|
429
|
-
|
420
|
+
amoeba do
|
421
|
+
include_association :tags
|
430
422
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
423
|
+
customize([
|
424
|
+
lambda do |orig_obj,copy_of_obj|
|
425
|
+
# good stuff goes here
|
426
|
+
end,
|
435
427
|
|
436
|
-
|
437
|
-
|
438
|
-
end
|
439
|
-
])
|
428
|
+
lambda do |orig_obj,copy_of_obj|
|
429
|
+
# more good stuff goes here
|
440
430
|
end
|
441
|
-
|
431
|
+
])
|
432
|
+
end
|
433
|
+
end
|
434
|
+
```
|
442
435
|
|
443
436
|
##### Override
|
444
437
|
|
445
438
|
Lambda blocks passed to customize run, by default, after all copying and field pre-processing. If you wish to run a method before any customization or field pre-processing, you may use `override` the cousin of `customize`. Usage is the same as above.
|
446
439
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
override(lambda { |original_post,new_post|
|
452
|
-
if original_post.foo == "bar"
|
453
|
-
new_post.baz = "qux"
|
454
|
-
end
|
455
|
-
})
|
440
|
+
```ruby
|
441
|
+
class Post < ActiveRecord::Base
|
442
|
+
amoeba do
|
443
|
+
prepend :title => "Hello world! "
|
456
444
|
|
457
|
-
|
445
|
+
override(lambda { |original_post,new_post|
|
446
|
+
if original_post.foo == "bar"
|
447
|
+
new_post.baz = "qux"
|
458
448
|
end
|
459
|
-
|
449
|
+
})
|
450
|
+
|
451
|
+
append :comments => "... know what I'm sayin?"
|
452
|
+
end
|
453
|
+
end
|
454
|
+
```
|
460
455
|
|
461
456
|
#### Chaining
|
462
457
|
|
463
458
|
You may apply a single preprocessor to multiple fields at once.
|
464
459
|
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
460
|
+
```ruby
|
461
|
+
class Post < ActiveRecord::Base
|
462
|
+
amoeba do
|
463
|
+
enable
|
464
|
+
prepend :title => "Copy of ", :contents => "Copied contents: "
|
465
|
+
end
|
466
|
+
end
|
467
|
+
```
|
471
468
|
|
472
469
|
#### Stacking
|
473
470
|
|
474
|
-
You may apply multiple
|
471
|
+
You may apply multiple preprocessing directives to a single model at once.
|
475
472
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
473
|
+
```ruby
|
474
|
+
class Post < ActiveRecord::Base
|
475
|
+
amoeba do
|
476
|
+
prepend :title => "Copy of ", :contents => "Original contents: "
|
477
|
+
append :contents => " (copied version)"
|
478
|
+
regex :contents => {:replace => /dog/, :with => 'cat'}
|
479
|
+
end
|
480
|
+
end
|
481
|
+
```
|
483
482
|
|
484
483
|
This example should result in something like this:
|
485
484
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
485
|
+
```ruby
|
486
|
+
post = Post.create(
|
487
|
+
:title => "Hello world",
|
488
|
+
:contents => "I like dogs, dogs are awesome."
|
489
|
+
)
|
490
490
|
|
491
|
-
|
491
|
+
new_post = post.amoeba_dup
|
492
492
|
|
493
|
-
|
494
|
-
|
493
|
+
new_post.title # "Copy of Hello world"
|
494
|
+
new_post.contents # "Original contents: I like cats, cats are awesome. (copied version)"
|
495
|
+
```
|
495
496
|
|
496
|
-
Like `nullify`, the preprocessing directives do not automatically enable the copying of associated child records. If only preprocessing directives are used and you do want to copy child records and no `
|
497
|
+
Like `nullify`, the preprocessing directives do not automatically enable the copying of associated child records. If only preprocessing directives are used and you do want to copy child records and no `include_association` or `exclude_association` list is provided, you must still explicitly enable the copying of child records by calling the enable method from within the amoeba block on your model.
|
497
498
|
|
498
499
|
### Precedence
|
499
500
|
|
500
|
-
You may use a combination of configuration methods within each model's amoeba block. Recognized association types take precedence over inclusion or exclusion lists. Inclusive style takes precedence over exclusive style, and these two explicit styles take precedence over the indiscriminate style. In other words, if you list fields to copy, amoeba will only copy the fields you list, or only copy the fields you don't exclude as the case may be. Additionally, if a field type is not recognized it will not be copied, regardless of whether it appears in an inclusion list. If you want amoeba to automatically copy all of your child records, do not list any fields using either `
|
501
|
+
You may use a combination of configuration methods within each model's amoeba block. Recognized association types take precedence over inclusion or exclusion lists. Inclusive style takes precedence over exclusive style, and these two explicit styles take precedence over the indiscriminate style. In other words, if you list fields to copy, amoeba will only copy the fields you list, or only copy the fields you don't exclude as the case may be. Additionally, if a field type is not recognized it will not be copied, regardless of whether it appears in an inclusion list. If you want amoeba to automatically copy all of your child records, do not list any fields using either `include_association` or `exclude_association`.
|
501
502
|
|
502
503
|
The following example syntax is perfectly valid, and will result in the usage of inclusive style. The order in which you call the configuration methods within the amoeba block does not matter:
|
503
504
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
505
|
+
```ruby
|
506
|
+
class Topic < ActiveRecord::Base
|
507
|
+
has_many :posts
|
508
|
+
end
|
509
|
+
|
510
|
+
class Post < ActiveRecord::Base
|
511
|
+
belongs_to :topic
|
512
|
+
has_many :comments
|
513
|
+
has_many :tags
|
514
|
+
has_many :authors
|
515
|
+
|
516
|
+
amoeba do
|
517
|
+
exclude_association :authors
|
518
|
+
include_association :tags
|
519
|
+
nullify :date_published
|
520
|
+
prepend :title => "Copy of "
|
521
|
+
append :contents => " (copied version)"
|
522
|
+
regex :contents => {:replace => /dog/, :with => 'cat'}
|
523
|
+
include_association :authors
|
524
|
+
enable
|
525
|
+
nullify :topic_id
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
class Comment < ActiveRecord::Base
|
530
|
+
belongs_to :post
|
531
|
+
end
|
532
|
+
```
|
530
533
|
|
531
534
|
This example will copy all of a post's tags and authors, but not its comments. It will also nullify the publishing date and dissociate the post from its original topic. It will also preprocess the post's fields as in the previous preprocessing example.
|
532
535
|
|
533
|
-
Note that, because of precedence, inclusive style is used and the list of exclude fields is never consulted. Additionally, the `enable` method is redundant because amoeba is automatically enabled when using `
|
536
|
+
Note that, because of precedence, inclusive style is used and the list of exclude fields is never consulted. Additionally, the `enable` method is redundant because amoeba is automatically enabled when using `include_association`.
|
534
537
|
|
535
|
-
The preprocessing directives are run after child records are copied
|
538
|
+
The preprocessing directives are run after child records are copied and are run in this order.
|
536
539
|
|
537
540
|
1. Null fields
|
538
541
|
2. Prepends
|
@@ -545,26 +548,28 @@ Preprocessing directives do not affect inclusion and exclusion lists.
|
|
545
548
|
|
546
549
|
You may cause amoeba to keep copying down the chain as far as you like, simply add amoeba blocks to each model you wish to have copy its children. Amoeba will automatically recurse into any enabled grandchildren and copy them as well.
|
547
550
|
|
548
|
-
|
549
|
-
|
551
|
+
```ruby
|
552
|
+
class Post < ActiveRecord::Base
|
553
|
+
has_many :comments
|
550
554
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
+
amoeba do
|
556
|
+
enable
|
557
|
+
end
|
558
|
+
end
|
555
559
|
|
556
|
-
|
557
|
-
|
558
|
-
|
560
|
+
class Comment < ActiveRecord::Base
|
561
|
+
belongs_to :post
|
562
|
+
has_many :ratings
|
559
563
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
+
amoeba do
|
565
|
+
enable
|
566
|
+
end
|
567
|
+
end
|
564
568
|
|
565
|
-
|
566
|
-
|
567
|
-
|
569
|
+
class Rating < ActiveRecord::Base
|
570
|
+
belongs_to :comment
|
571
|
+
end
|
572
|
+
```
|
568
573
|
|
569
574
|
In this example, when a post is copied, amoeba will copy each all of a post's comments and will also copy each comment's ratings.
|
570
575
|
|
@@ -572,142 +577,150 @@ In this example, when a post is copied, amoeba will copy each all of a post's co
|
|
572
577
|
|
573
578
|
Using the `has_one :through` association is simple, just be sure to enable amoeba on the each model with a `has_one` association and amoeba will automatically and recursively drill down, like so:
|
574
579
|
|
575
|
-
|
576
|
-
|
577
|
-
|
580
|
+
```ruby
|
581
|
+
class Supplier < ActiveRecord::Base
|
582
|
+
has_one :account
|
583
|
+
has_one :history, :through => :account
|
578
584
|
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
585
|
+
amoeba do
|
586
|
+
enable
|
587
|
+
end
|
588
|
+
end
|
583
589
|
|
584
|
-
|
585
|
-
|
586
|
-
|
590
|
+
class Account < ActiveRecord::Base
|
591
|
+
belongs_to :supplier
|
592
|
+
has_one :history
|
587
593
|
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
594
|
+
amoeba do
|
595
|
+
enable
|
596
|
+
end
|
597
|
+
end
|
592
598
|
|
593
|
-
|
594
|
-
|
595
|
-
|
599
|
+
class History < ActiveRecord::Base
|
600
|
+
belongs_to :account
|
601
|
+
end
|
602
|
+
```
|
596
603
|
|
597
604
|
### Has Many Through
|
598
605
|
|
599
606
|
Copying of `has_many :through` associations works automatically. They perform the copy in the same way as the `has_and_belongs_to_many` association, meaning the actual child records are not copied, but rather the associations are simply maintained. You can add some field preprocessors to the middle model if you like but this is not strictly necessary:
|
600
607
|
|
601
|
-
|
602
|
-
|
603
|
-
|
608
|
+
```ruby
|
609
|
+
class Assembly < ActiveRecord::Base
|
610
|
+
has_many :manifests
|
611
|
+
has_many :parts, :through => :manifests
|
604
612
|
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
613
|
+
amoeba do
|
614
|
+
enable
|
615
|
+
end
|
616
|
+
end
|
609
617
|
|
610
|
-
|
611
|
-
|
612
|
-
|
618
|
+
class Manifest < ActiveRecord::Base
|
619
|
+
belongs_to :assembly
|
620
|
+
belongs_to :part
|
613
621
|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
622
|
+
amoeba do
|
623
|
+
prepend :notes => "Copy of "
|
624
|
+
end
|
625
|
+
end
|
618
626
|
|
619
|
-
|
620
|
-
|
621
|
-
|
627
|
+
class Part < ActiveRecord::Base
|
628
|
+
has_many :manifests
|
629
|
+
has_many :assemblies, :through => :manifests
|
622
630
|
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
631
|
+
amoeba do
|
632
|
+
enable
|
633
|
+
end
|
634
|
+
end
|
635
|
+
```
|
627
636
|
|
628
637
|
### On The Fly Configuration
|
629
638
|
|
630
639
|
You may control how amoeba copies your object, on the fly, by passing a configuration block to the model's amoeba method. The configuration method is static but the configuration is applied on a per instance basis.
|
631
640
|
|
632
|
-
|
633
|
-
|
641
|
+
```ruby
|
642
|
+
class Post < ActiveRecord::Base
|
643
|
+
has_many :comments
|
634
644
|
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
645
|
+
amoeba do
|
646
|
+
enable
|
647
|
+
prepend :title => "Copy of "
|
648
|
+
end
|
649
|
+
end
|
640
650
|
|
641
|
-
|
642
|
-
|
643
|
-
|
651
|
+
class Comment < ActiveRecord::Base
|
652
|
+
belongs_to :post
|
653
|
+
end
|
644
654
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
655
|
+
class PostsController < ActionController
|
656
|
+
def duplicate_a_post
|
657
|
+
old_post = Post.create(
|
658
|
+
:title => "Hello world",
|
659
|
+
:contents => "Lorum ipsum"
|
660
|
+
)
|
651
661
|
|
652
|
-
|
653
|
-
|
654
|
-
|
662
|
+
old_post.class.amoeba do
|
663
|
+
prepend :contents => "Here's a copy: "
|
664
|
+
end
|
655
665
|
|
656
|
-
|
666
|
+
new_post = old_post.amoeba_dup
|
657
667
|
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
668
|
+
new_post.title # should be "Copy of Hello world"
|
669
|
+
new_post.contents # should be "Here's a copy: Lorum ipsum"
|
670
|
+
new_post.save
|
671
|
+
end
|
672
|
+
end
|
673
|
+
```
|
663
674
|
|
664
675
|
### Inheritance
|
665
676
|
|
666
677
|
If you are using the Single Table Inheritance provided by ActiveRecord, you may cause amoeba to automatically process child classes in the same way as their parents. All you need to do is call the `propagate` method within the amoeba block of the parent class and all child classes should copy in a similar manner.
|
667
678
|
|
668
|
-
|
669
|
-
|
679
|
+
```ruby
|
680
|
+
create_table :products, :force => true do |t|
|
681
|
+
t.string :type # this is the STI column
|
670
682
|
|
671
|
-
|
672
|
-
|
673
|
-
|
683
|
+
# these belong to all products
|
684
|
+
t.string :title
|
685
|
+
t.decimal :price
|
674
686
|
|
675
|
-
|
676
|
-
|
677
|
-
|
687
|
+
# these are for shirts only
|
688
|
+
t.decimal :sleeve_length
|
689
|
+
t.decimal :collar_size
|
678
690
|
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
691
|
+
# these are for computers only
|
692
|
+
t.integer :ram_size
|
693
|
+
t.integer :hard_drive_size
|
694
|
+
end
|
683
695
|
|
684
|
-
|
685
|
-
|
686
|
-
|
696
|
+
class Product < ActiveRecord::Base
|
697
|
+
has_many :images
|
698
|
+
has_and_belongs_to_many :categories
|
687
699
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
700
|
+
amoeba do
|
701
|
+
enable
|
702
|
+
propagate
|
703
|
+
end
|
704
|
+
end
|
693
705
|
|
694
|
-
|
695
|
-
|
706
|
+
class Shirt < Product
|
707
|
+
end
|
696
708
|
|
697
|
-
|
698
|
-
|
709
|
+
class Computer < Product
|
710
|
+
end
|
699
711
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
712
|
+
class ProductsController
|
713
|
+
def some_method
|
714
|
+
my_shirt = Shirt.find(1)
|
715
|
+
my_shirt.amoeba_dup
|
716
|
+
my_shirt.save
|
705
717
|
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
718
|
+
# this shirt should now:
|
719
|
+
# - have its own copy of all parent images
|
720
|
+
# - be in the same categories as the parent
|
721
|
+
end
|
722
|
+
end
|
723
|
+
```
|
711
724
|
|
712
725
|
This example should duplicate all the images and sections associated with this Shirt, which is a child of Product
|
713
726
|
|
@@ -721,45 +734,49 @@ You may change this behavior, the so called "parenting style", to give preferenc
|
|
721
734
|
|
722
735
|
The `:relaxed` parenting style will prefer parent settings.
|
723
736
|
|
724
|
-
|
725
|
-
|
726
|
-
|
737
|
+
```ruby
|
738
|
+
class Product < ActiveRecord::Base
|
739
|
+
has_many :images
|
740
|
+
has_and_belongs_to_many :sections
|
727
741
|
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
742
|
+
amoeba do
|
743
|
+
exclude_association :images
|
744
|
+
propagate :relaxed
|
745
|
+
end
|
746
|
+
end
|
733
747
|
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
748
|
+
class Shirt < Product
|
749
|
+
include_association :images
|
750
|
+
include_association :sections
|
751
|
+
prepend :title => "Copy of "
|
752
|
+
end
|
753
|
+
```
|
739
754
|
|
740
|
-
In this example, the conflicting `
|
755
|
+
In this example, the conflicting `include_association` settings on the child will be ignored and the parent `exclude_association` setting will be used, while the `prepend` setting on the child will be honored because it doesn't conflict with the parent.
|
741
756
|
|
742
757
|
##### Strict Parenting
|
743
758
|
|
744
759
|
The `:strict` style will ignore child settings altogether and inherit any parent settings.
|
745
760
|
|
746
|
-
|
747
|
-
|
748
|
-
|
761
|
+
```ruby
|
762
|
+
class Product < ActiveRecord::Base
|
763
|
+
has_many :images
|
764
|
+
has_and_belongs_to_many :sections
|
749
765
|
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
766
|
+
amoeba do
|
767
|
+
exclude_association :images
|
768
|
+
propagate :strict
|
769
|
+
end
|
770
|
+
end
|
755
771
|
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
772
|
+
class Shirt < Product
|
773
|
+
include_association :images
|
774
|
+
include_association :sections
|
775
|
+
prepend :title => "Copy of "
|
776
|
+
end
|
777
|
+
```
|
761
778
|
|
762
|
-
In this example, the only processing that will happen when a Shirt is duplicated is whatever processing is allowed by the parent. So in this case the parent's `
|
779
|
+
In this example, the only processing that will happen when a Shirt is duplicated is whatever processing is allowed by the parent. So in this case the parent's `exclude_association` directive takes precedence over the child's `include_association` settings, and not only that, but none of the other settings for the child are used either. The `prepend` setting of the child is completely ignored.
|
763
780
|
|
764
781
|
##### Parenting and Precedence
|
765
782
|
|
@@ -779,85 +796,274 @@ This means that, for example:
|
|
779
796
|
|
780
797
|
This version will use both the parent and child settings, so both the images and sections will be copied.
|
781
798
|
|
782
|
-
|
783
|
-
|
784
|
-
|
799
|
+
```ruby
|
800
|
+
class Product < ActiveRecord::Base
|
801
|
+
has_many :images
|
802
|
+
has_and_belongs_to_many :sections
|
785
803
|
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
804
|
+
amoeba do
|
805
|
+
include_association :images
|
806
|
+
propagate
|
807
|
+
end
|
808
|
+
end
|
791
809
|
|
792
|
-
|
793
|
-
|
794
|
-
|
810
|
+
class Shirt < Product
|
811
|
+
include_association :sections
|
812
|
+
end
|
813
|
+
```
|
795
814
|
|
796
815
|
The next version will use only the child settings because passing an array will override any previous settings rather than adding to them and the child config takes precedence in the `submissive` parenting style. So in this case only the sections will be copied.
|
797
816
|
|
798
|
-
|
799
|
-
|
800
|
-
|
817
|
+
```ruby
|
818
|
+
class Product < ActiveRecord::Base
|
819
|
+
has_many :images
|
820
|
+
has_and_belongs_to_many :sections
|
801
821
|
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
822
|
+
amoeba do
|
823
|
+
include_association :images
|
824
|
+
propagate
|
825
|
+
end
|
826
|
+
end
|
807
827
|
|
808
|
-
|
809
|
-
|
810
|
-
|
828
|
+
class Shirt < Product
|
829
|
+
include_association [:sections]
|
830
|
+
end
|
831
|
+
```
|
811
832
|
|
812
833
|
##### A Relaxed Override Example
|
813
834
|
|
814
835
|
This version will use both the parent and child settings, so both the images and sections will be copied.
|
815
836
|
|
816
|
-
|
817
|
-
|
818
|
-
|
837
|
+
```ruby
|
838
|
+
class Product < ActiveRecord::Base
|
839
|
+
has_many :images
|
840
|
+
has_and_belongs_to_many :sections
|
819
841
|
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
842
|
+
amoeba do
|
843
|
+
include_association :images
|
844
|
+
propagate :relaxed
|
845
|
+
end
|
846
|
+
end
|
825
847
|
|
826
|
-
|
827
|
-
|
828
|
-
|
848
|
+
class Shirt < Product
|
849
|
+
include_association :sections
|
850
|
+
end
|
851
|
+
```
|
829
852
|
|
830
853
|
The next version will use only the parent settings because passing an array will override any previous settings rather than adding to them and the parent config takes precedence in the `relaxed` parenting style. So in this case only the images will be copied.
|
831
854
|
|
832
|
-
|
833
|
-
|
834
|
-
|
855
|
+
```ruby
|
856
|
+
class Product < ActiveRecord::Base
|
857
|
+
has_many :images
|
858
|
+
has_and_belongs_to_many :sections
|
835
859
|
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
860
|
+
amoeba do
|
861
|
+
include_association [:images]
|
862
|
+
propagate
|
863
|
+
end
|
864
|
+
end
|
841
865
|
|
842
|
-
|
843
|
-
|
844
|
-
|
866
|
+
class Shirt < Product
|
867
|
+
include_association :sections
|
868
|
+
end
|
869
|
+
```
|
870
|
+
|
871
|
+
### Validating Nested Attributes
|
872
|
+
|
873
|
+
If you end up with some validation issues when trying to validate the presence of a child's `belongs_to` association, just be sure to include the `:inverse_of` declaration on your relationships and all should be well.
|
874
|
+
|
875
|
+
For example this will throw a validation error saying that your posts are invalid:
|
876
|
+
|
877
|
+
```ruby
|
878
|
+
class Author < ActiveRecord::Base
|
879
|
+
has_many :posts
|
880
|
+
|
881
|
+
amoeba do
|
882
|
+
enable
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
class Post < ActiveRecord::Base
|
887
|
+
belongs_to :author
|
888
|
+
validates_presence_of :author
|
889
|
+
|
890
|
+
amoeba do
|
891
|
+
enable
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
author = Author.find(1)
|
896
|
+
author.amoeba_dup
|
897
|
+
|
898
|
+
author.save # this will fail validation
|
899
|
+
```
|
900
|
+
|
901
|
+
Where this will work fine:
|
902
|
+
|
903
|
+
```ruby
|
904
|
+
class Author < ActiveRecord::Base
|
905
|
+
has_many :posts, :inverse_of => :author
|
906
|
+
|
907
|
+
amoeba do
|
908
|
+
enable
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
class Post < ActiveRecord::Base
|
913
|
+
belongs_to :author, :inverse_of => :posts
|
914
|
+
validates_presence_of :author
|
915
|
+
|
916
|
+
amoeba do
|
917
|
+
enable
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
921
|
+
author = Author.find(1)
|
922
|
+
author.amoeba_dup
|
923
|
+
|
924
|
+
author.save # this will pass validation
|
925
|
+
```
|
926
|
+
|
927
|
+
This issue is not amoeba specific and also occurs when creating new objects using `accepts_nested_attributes_for`, like this:
|
928
|
+
|
929
|
+
```ruby
|
930
|
+
class Author < ActiveRecord::Base
|
931
|
+
has_many :posts
|
932
|
+
accepts_nested_attributes_for :posts
|
933
|
+
end
|
934
|
+
|
935
|
+
class Post < ActiveRecord::Base
|
936
|
+
belongs_to :author
|
937
|
+
validates_presence_of :author
|
938
|
+
end
|
939
|
+
|
940
|
+
# this will fail validation
|
941
|
+
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
942
|
+
```
|
943
|
+
|
944
|
+
This issue with `accepts_nested_attributes_for` can also be solved by using `:inverse_of`, like this:
|
945
|
+
|
946
|
+
```ruby
|
947
|
+
class Author < ActiveRecord::Base
|
948
|
+
has_many :posts, :inverse_of => :author
|
949
|
+
accepts_nested_attributes_for :posts
|
950
|
+
end
|
951
|
+
|
952
|
+
class Post < ActiveRecord::Base
|
953
|
+
belongs_to :author, :inverse_of => :posts
|
954
|
+
validates_presence_of :author
|
955
|
+
end
|
956
|
+
|
957
|
+
# this will pass validation
|
958
|
+
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
959
|
+
```
|
960
|
+
|
961
|
+
The crux of the issue is that upon duplication, the new `Author` instance does not yet have an ID because it has not yet been persisted, so the `:posts` do not yet have an `:author_id` either, and thus no `:author` and thus they will fail validation. This issue may likely affect amoeba usage so if you get some validation failures, be sure to add `:inverse_of` to your models.
|
962
|
+
|
963
|
+
|
964
|
+
## Cloning using custom method
|
965
|
+
|
966
|
+
If you need to clone model with custom method you can use `through`:
|
967
|
+
|
968
|
+
```ruby
|
969
|
+
class ChildPrototype < ActiveRecord::Base
|
970
|
+
amoeba do
|
971
|
+
through :become_child
|
972
|
+
end
|
973
|
+
|
974
|
+
def become_child
|
975
|
+
self.dup.becomes(Child)
|
976
|
+
end
|
977
|
+
end
|
978
|
+
|
979
|
+
class Child < ChildPrototype
|
980
|
+
end
|
981
|
+
```
|
982
|
+
|
983
|
+
After cloning we will get instance of `Child` instead of `ChildPrototype`
|
984
|
+
|
985
|
+
## Remapping associations
|
986
|
+
|
987
|
+
If you will need to do complex cloning with remapping associations name you can user `remapper`:
|
988
|
+
|
989
|
+
```ruby
|
990
|
+
class ObjectPrototype < ActiveRecord::Base
|
991
|
+
has_many :child_prototypes
|
992
|
+
|
993
|
+
amoeba do
|
994
|
+
method :become_real
|
995
|
+
remapper :remap_associations
|
996
|
+
end
|
997
|
+
|
998
|
+
def become_real
|
999
|
+
self.dup().becomes( RealObject )
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
def remap_associations( name )
|
1003
|
+
:childs if name == :child_prototypes
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
class RealObject < ObjectPrototype
|
1008
|
+
has_many :childs
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
class ChildPrototype < ActiveRecord::Base
|
1012
|
+
amoeba do
|
1013
|
+
method :become_child
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
def become_child
|
1017
|
+
self.dup().becomes( Child )
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
class Child < ChildPrototype
|
1022
|
+
end
|
1023
|
+
```
|
1024
|
+
|
1025
|
+
In result we will get next:
|
1026
|
+
|
1027
|
+
```ruby
|
1028
|
+
prototype = ObjectPrototype.new
|
1029
|
+
prototype.child_prototypes << ChildPrototype.new
|
1030
|
+
object = prototype.amoeba_dup
|
1031
|
+
object.class # => RealObject
|
1032
|
+
object.childs.first.class #=> Child
|
1033
|
+
```
|
845
1034
|
|
846
1035
|
## Configuration Reference
|
847
1036
|
|
848
1037
|
Here is a static reference to the available configuration methods, usable within the amoeba block on your rails models.
|
849
1038
|
|
1039
|
+
### through
|
1040
|
+
|
1041
|
+
Set method what we will use for cloning model instead of `dup`.
|
1042
|
+
|
1043
|
+
for example:
|
1044
|
+
|
1045
|
+
```ruby
|
1046
|
+
amoeba do
|
1047
|
+
through :supper_pupper_dup
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
def supper_pupper_dup
|
1051
|
+
puts "multiplied by budding"
|
1052
|
+
self.dup
|
1053
|
+
end
|
1054
|
+
```
|
1055
|
+
|
850
1056
|
### Controlling Associations
|
851
1057
|
|
852
1058
|
#### enable
|
853
1059
|
|
854
|
-
Enables amoeba in the default style of copying all known associated child records. Using the enable method is only required if you wish to enable amoeba but you are not using either the `
|
1060
|
+
Enables amoeba in the default style of copying all known associated child records. Using the enable method is only required if you wish to enable amoeba but you are not using either the `include_association` or `exclude_association` directives. If you use either inclusive or exclusive style, amoeba is automatically enabled for you, so calling `enable` would be redundant, though it won't hurt.
|
855
1061
|
|
856
|
-
####
|
1062
|
+
#### include_association
|
857
1063
|
|
858
1064
|
Adds a field to the list of fields which should be copied. All associations not in this list will not be copied. This method may be called multiple times, once per desired field, or you may pass an array of field names. Passing a single symbol will add to the list of included fields. Passing an array will empty the list and replace it with the array you pass.
|
859
1065
|
|
860
|
-
####
|
1066
|
+
#### exclude_association
|
861
1067
|
|
862
1068
|
Adds a field to the list of fields which should not be copied. Only the associations that are not in this list will be copied. This method may be called multiple times, once per desired field, or you may pass an array of field names. Passing a single symbol will add to the list of excluded fields. Passing an array will empty the list and replace it with the array you pass.
|
863
1069
|
|
@@ -873,9 +1079,11 @@ Here is a static reference to the available configuration methods, usable within
|
|
873
1079
|
|
874
1080
|
for example
|
875
1081
|
|
876
|
-
|
877
|
-
|
878
|
-
|
1082
|
+
```ruby
|
1083
|
+
amoeba do
|
1084
|
+
propagate :strict
|
1085
|
+
end
|
1086
|
+
```
|
879
1087
|
|
880
1088
|
will choose the strict parenting style of inherited settings.
|
881
1089
|
|
@@ -887,12 +1095,30 @@ Here is a static reference to the available configuration methods, usable within
|
|
887
1095
|
|
888
1096
|
for example:
|
889
1097
|
|
890
|
-
|
891
|
-
|
892
|
-
|
1098
|
+
```ruby
|
1099
|
+
amoeba do
|
1100
|
+
raised :relaxed
|
1101
|
+
end
|
1102
|
+
```
|
893
1103
|
|
894
1104
|
will choose the relaxed parenting style of inherited settings for this child. A parenting style set via the `raised` method takes precedence over the parenting style set using the `propagate` method.
|
895
1105
|
|
1106
|
+
#### remapper
|
1107
|
+
|
1108
|
+
Set the method what will be used for remapping of association name. Method will have one argument - association name as Symbol. If method will return nil then association will not be remapped.
|
1109
|
+
|
1110
|
+
for example:
|
1111
|
+
|
1112
|
+
```ruby
|
1113
|
+
amoeba do
|
1114
|
+
remapper :childs_to_parents
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
def childs_to_parents(association_name)
|
1118
|
+
:parents if association_name == :childs
|
1119
|
+
end
|
1120
|
+
```
|
1121
|
+
|
896
1122
|
### Pre-Processing Fields
|
897
1123
|
|
898
1124
|
#### nullify
|
@@ -909,15 +1135,21 @@ Here is a static reference to the available configuration methods, usable within
|
|
909
1135
|
|
910
1136
|
#### set
|
911
1137
|
|
912
|
-
Set a field to a given value. This
|
1138
|
+
Set a field to a given value. This should work for almost any type of field. Accepts a hash of fields and the values you want them set to.. The keys are the field names and the values are the prefix strings. An example would be to add " (copied version)" to your description field. Don't forget to add a leading space if you want it. Passing a hash will add each key value pair to the list of append directives. If you wish to empty the list of directives, you may pass the hash inside of an array like this `[{:approval_state => "open_for_editing"}]`.
|
913
1139
|
|
914
1140
|
#### regex
|
915
1141
|
|
916
1142
|
Globally search and replace the field for a given pattern. Accepts a hash of fields to run search and replace upon. The keys are the field names and the values are each a hash with information about what to find and what to replace it with. in the form of . An example would be to replace all occurrences of the word "dog" with the word "cat", the parameter hash would look like this `:contents => {:replace => /dog/, :with => "cat"}`. Passing a hash will add each key value pair to the list of regex directives. If you wish to empty the list of directives, you may pass the hash inside of an array like this `[{:contents => {:replace => /dog/, :with => "cat"}]`.
|
917
1143
|
|
1144
|
+
#### override
|
1145
|
+
|
1146
|
+
Runs a custom method so you can do basically whatever you want. All you need to do is pass a lambda block or an array of lambda blocks that take two parameters, the original object and the new object copy. These blocks will run before any other duplication or field processing.
|
1147
|
+
|
1148
|
+
This method may be called multiple times, once per desired customizer block, or you may pass an array of lambdas. Passing a single lambda will add to the list of processing directives. Passing an array will empty the list and replace it with the array you pass.
|
1149
|
+
|
918
1150
|
#### customize
|
919
1151
|
|
920
|
-
Runs a custom method so you can do basically whatever you want. All you need to do is pass a lambda block or an array of lambda blocks that take two parameters, the original object and the new object copy
|
1152
|
+
Runs a custom method so you can do basically whatever you want. All you need to do is pass a lambda block or an array of lambda blocks that take two parameters, the original object and the new object copy. These blocks will run after all copying and field processing.
|
921
1153
|
|
922
1154
|
This method may be called multiple times, once per desired customizer block, or you may pass an array of lambdas. Passing a single lambda will add to the list of processing directives. Passing an array will empty the list and replace it with the array you pass.
|
923
1155
|
|
@@ -933,7 +1165,9 @@ The behavior when copying polymorphic `has_many` associations is also undefined.
|
|
933
1165
|
|
934
1166
|
You may run the rspec tests like this:
|
935
1167
|
|
936
|
-
|
1168
|
+
```sh
|
1169
|
+
bundle exec rspec spec
|
1170
|
+
```
|
937
1171
|
|
938
1172
|
### TODO
|
939
1173
|
|