active_merge 1.0.5 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9908a773d23bf5b0b67850538549bf130646b257
4
- data.tar.gz: e61c2879ca3ff6a256ac575651c69432b97c3c15
3
+ metadata.gz: 3a852fec8deb9d07be3fc9c377d1094a12a3574c
4
+ data.tar.gz: 9dc95d04b550e50ffbf1250c11ee578a35c60729
5
5
  SHA512:
6
- metadata.gz: d189fc4e6e22e3806c1bcf7350130718c4e85170c6d9b51924a7b206cbbdbec9ecae588d339a36bec6fc2650b7a75d3883d51d718663159226b94e7cae6b4511
7
- data.tar.gz: eccd6bbd86184af049cb31f3229b4c575ab9ba478c7b0b4a7e3ba97af443ec62467424761f25f8e5bd89ea9c3446dc000f3f73b789a787a1c16d13eb961fd1ac
6
+ metadata.gz: 2c57dcfd9df06c76630812169fc38e815b059b33e23b6f9c623eb3324469177ed4f41384ac5eda12ed199e82770b5a4f0bbbcb3c55d239b7b946e6e364edfaf7
7
+ data.tar.gz: 5a606c8a1aa4ade555780ecad0dee9e303ae76b3a05c118ce42150b4b8d46485ab82009aa3762d52380110772d6d6fca16828db7380e8b9e4177a803a63d1c65
data/README.rdoc CHANGED
@@ -7,14 +7,17 @@
7
7
 
8
8
  Declares the <tt>ActiveMerge</tt> module for extending ActiveRecord models.
9
9
 
10
+ == Main usage
11
+
10
12
  The module contains the <tt>merge_all</tt> class method for merging
11
13
  class instances into the first one.
12
14
 
13
15
  When merging a list of instances:
16
+
14
17
  * all "has_many" relatives are reattached to the instance with the lowest id
15
18
  * all the instances except for the first one (with the lowest id) are deleted
16
19
 
17
- == Example
20
+ === Example
18
21
 
19
22
  class Post < ActiveRecord
20
23
  extend ActiveMerge
@@ -26,6 +29,23 @@ When merging a list of instances:
26
29
  # The other posts will be deleted after their comment are reattached
27
30
  # to the first post.
28
31
 
32
+ == Skipping validations and callbacks
33
+
34
+ You can use the <tt>validate: false</tt> option.
35
+
36
+ With this option set any activerecord validation and callback are skipped.
37
+
38
+ Post.all.merge_all validate: false
39
+
40
+ **Warning**
41
+
42
+ Only activerecord validations and callbacks are skipped! Raising other errors
43
+ (by database etc.) will cause all changes to roll back as before.
44
+
45
+ == Version changes
46
+
47
+ See the CHANGELOG[link:CHANGELOG.rdoc].
48
+
29
49
  == License
30
50
 
31
- This project rocks and uses MIT-LICENSE[link:LICENSE].
51
+ This project rocks and uses MIT LICENSE[link:LICENSE].
@@ -48,7 +48,7 @@ module ActiveMerge
48
48
  # 5.times.each{ scotland.shires.create! }
49
49
  #
50
50
  # # Lets merge all the kingdoms:
51
- # Service.new(Kingdom.all).submit!
51
+ # Service.new(Kingdom.all).provide
52
52
  #
53
53
  # # Now union Britain (because it is Britain that was created first)
54
54
  # # has all those 15 shires and 130 thousand men
@@ -61,8 +61,8 @@ module ActiveMerge
61
61
  #
62
62
  # == Warning!
63
63
  #
64
- # The merge provided as a whole transaction. In case any error occures, all
65
- # the changes rolled back.
64
+ # The merge provided as a whole transaction. In case of any error, all
65
+ # changes roll back.
66
66
  #
67
67
  # Let (see the example above) the shire cannot be rebount to another kingdom:
68
68
  #
@@ -70,10 +70,16 @@ module ActiveMerge
70
70
  # attr_readonly :kingdom_id
71
71
  # end
72
72
  #
73
- # then merging won't be finished.
73
+ # In this case the merge won't be finished. Not only shires, but also
74
+ # scots remain living in their old good Scotland!
74
75
  #
75
- # Not only shires, but also the scots remain living in their Scotland,
76
- # not in the United Kingdom!
76
+ # == Skipping activerecord validations
77
+ #
78
+ # You can use the <tt>validate: false</tt> option.
79
+ #
80
+ # With this option set any activerecord validation and callback are skipped.
81
+ #
82
+ # Service.new(Kingdom.all).provide validate: false
77
83
  #
78
84
  class Service < ActivePatterns::BaseService
79
85
  include ActiveModel::Validations
@@ -87,11 +93,11 @@ module ActiveMerge
87
93
  validates :items, presence: true
88
94
 
89
95
  # Merges all the #items to the #item as a whole transaction
90
- def provide
96
+ def provide(options = {})
91
97
  transaction do
92
98
  items.each do |item|
93
99
  service = SimpleService.new(self.item, item)
94
- change(service) { service.provide }
100
+ change(service) { service.provide(options) }
95
101
  end
96
102
  end
97
103
  end
@@ -27,10 +27,10 @@ module ActiveMerge
27
27
 
28
28
  validates :second, presence: true
29
29
 
30
- def provide
30
+ def provide(options = {})
31
31
  transaction do
32
- Links.new(second).each { |item, key| rebind(item, key) }
33
- change(second) { second.destroy! }
32
+ Links.new(second).each { |item, key| rebind(item, key, options) }
33
+ remove(options)
34
34
  end
35
35
  end
36
36
 
@@ -63,11 +63,16 @@ module ActiveMerge
63
63
  end
64
64
  end
65
65
 
66
+ # Deletes or destroys second object
67
+ def remove(validate: true)
68
+ change(second) { validate ? second.destroy! : second.delete }
69
+ end
70
+
66
71
  # Re-assigns given object to the #first
67
- def rebind(item, key)
72
+ def rebind(item, key, options)
68
73
  change item do
69
74
  item.send key, first.id
70
- item.save!
75
+ item.save! options
71
76
  end
72
77
  end
73
78
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveMerge
2
- VERSION = "1.0.5"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/active_merge.rb CHANGED
@@ -20,9 +20,15 @@ module ActiveMerge
20
20
  # Lord.all.merge_all # => merges all the class instances
21
21
  # Lord.where("id > :id", id: 100) # => merges instances with id > 100
22
22
  #
23
+ # You can use the <tt>validate: false</tt> option.
24
+ #
25
+ # With this option set any activerecord validation and callback are skipped.
26
+ #
27
+ # Post.all.merge_all validate: false
28
+ #
23
29
  # See details in <tt>ActiveMerge::Service#provide</tt> documentation.
24
30
  #
25
- def merge_all
26
- ActiveMerge::Service.new(all).provide
31
+ def merge_all(options = {})
32
+ ActiveMerge::Service.new(all).provide(options)
27
33
  end
28
34
  end
@@ -146,58 +146,184 @@ module ActiveMerge
146
146
  let!(:domains) { lords.map{ |lord| lord.domains.create! }}
147
147
  let!(:men) { lords.map{ |lord| lord.men.create! }}
148
148
  let!(:service) { Service.new lords }
149
+
150
+ context "if :validate option isn't set" do
149
151
 
150
- context "если перепривязка разрешена" do
152
+ context "and no exceptions raised:" do
151
153
 
152
- it "не вызывает исключений" do
153
- expect{ service.provide }.not_to raise_error
154
+ it "merges the objects" do
155
+ service.provide
156
+ Lord.count.should eq 1
157
+ Lord.first.domains.count.should eq 2
158
+ Lord.first.men.count.should eq 2
159
+ end
160
+ end
161
+
162
+ context "and the service's own validation returns false:" do
163
+
164
+ before { service.stub(:valid?).and_return false }
165
+
166
+ it "raises an exception" do
167
+ expect{ service.provide }.to raise_error
168
+ end
169
+
170
+ it "doesn't make any change to db" do
171
+ expect{ begin; service.provide; rescue; end }.not_to change{ Lord.all.to_a }
172
+ expect{ begin; service.provide; rescue; end }.not_to change{ Domain.all.to_a }
173
+ expect{ begin; service.provide; rescue; end }.not_to change{ Man.all.to_a }
174
+ end
175
+ end
176
+
177
+ context "and a validation returns false when rebinding a link:" do
178
+
179
+ before do
180
+ Man.any_instance.stub(:valid?).and_return false
181
+ Man.any_instance.stub(:errors).and_return({ base: "record_invalid" })
182
+ end
183
+
184
+ it "raises an exception" do
185
+ expect{ service.provide }.to raise_error
186
+ end
187
+
188
+ it "doesn't make any change to db" do
189
+ expect{ begin; service.provide; rescue; end }.not_to change{ Lord.all.to_a }
190
+ expect{ begin; service.provide; rescue; end }.not_to change{ Domain.all.to_a }
191
+ expect{ begin; service.provide; rescue; end }.not_to change{ Man.all.to_a }
192
+ end
193
+
194
+ it "adds corresponding errors to the #errors" do
195
+ begin; service.provide; rescue; end
196
+ service.errors.should_not be_blank
197
+ end
154
198
  end
155
199
 
156
- it "объединяет записи" do
157
- begin; service.provide; rescue; end
158
- Lord.count.should eq 1
159
- Lord.first.domains.count.should eq 2
160
- Lord.first.men.count.should eq 2
200
+ context "and a callback returns false when destroying an object:" do
201
+
202
+ before do
203
+ Lord.before_destroy(){ false }
204
+ Lord.any_instance.stub(:errors).and_return({ base: "record_invalid" })
205
+ end
206
+ after{ Lord.reset_callbacks(:destroy) }
207
+
208
+ it "raises an exception" do
209
+ expect{ service.provide }.to raise_error
210
+ end
211
+
212
+ it "doesn't make any change to db" do
213
+ expect{ begin; service.provide; rescue; end }.not_to change{ Lord.all.to_a }
214
+ expect{ begin; service.provide; rescue; end }.not_to change{ Domain.all.to_a }
215
+ expect{ begin; service.provide; rescue; end }.not_to change{ Man.all.to_a }
216
+ end
217
+
218
+ it "adds corresponding errors to the #errors" do
219
+ begin; service.provide; rescue; end
220
+ service.errors.should_not be_blank
221
+ end
161
222
  end
162
223
  end
163
224
 
164
- context "если перепривязка не может быть выполнена" do
225
+ context "if :validate option is set to false" do
226
+
227
+ context "and no exceptions raised:" do
165
228
 
166
- before do
167
- service.items.last.stub(:destroy!).and_raise
168
- service.items.last.stub(:errors).and_return({ base: "Удаление запрещено." })
229
+ it "merges the objects" do
230
+ service.provide validate: false
231
+ Lord.count.should eq 1
232
+ Lord.first.domains.count.should eq 2
233
+ Lord.first.men.count.should eq 2
234
+ end
169
235
  end
170
236
 
171
- it "вызывает исключение" do
172
- expect{ service.provide }.to raise_error
237
+ context "and a validation returns false when rebinding a link:" do
238
+
239
+ before do
240
+ Man.any_instance.stub(:valid?).and_return false
241
+ Man.any_instance.stub(:errors).and_return({ base: "record_invalid" })
242
+ end
243
+
244
+ it "merges the objects" do
245
+ service.provide validate: false
246
+ Lord.count.should eq 1
247
+ Lord.first.domains.count.should eq 2
248
+ Lord.first.men.count.should eq 2
249
+ end
173
250
  end
174
251
 
175
- it "не объединяет записи" do
176
- begin; service.provide; rescue; end
177
- Lord.count.should eq 2
178
- Lord.all.each do |lord|
179
- lord.domains.count.should eq 1
180
- lord.men.count.should eq 1
252
+ context "and a callback returns false when destroying an object:" do
253
+
254
+ before do
255
+ Lord.before_destroy(){ false }
256
+ Lord.any_instance.stub(:errors).and_return({ base: "record_invalid" })
257
+ end
258
+ after{ Lord.reset_callbacks(:destroy) }
259
+
260
+ it "merges the objects" do
261
+ service.provide validate: false
262
+ Lord.count.should eq 1
263
+ Lord.first.domains.count.should eq 2
264
+ Lord.first.men.count.should eq 2
181
265
  end
182
266
  end
183
267
 
184
- it "добавляет ошибки в массив" do
185
- begin; service.provide; rescue; end
186
- service.errors.should_not be_blank
268
+ context "and the service's own validation returns false:" do
269
+
270
+ before { service.stub(:valid?).and_return false }
271
+
272
+ it "raises an exception" do
273
+ expect{ service.provide validate: false }.to raise_error
274
+ end
275
+
276
+ it "doesn't make any change to db" do
277
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Lord.all.to_a }
278
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Domain.all.to_a }
279
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Man.all.to_a }
280
+ end
187
281
  end
188
- end
189
282
 
190
- context "если атрибут #items пуст" do
283
+ context "and db recording fails when rebinding a link:" do
191
284
 
192
- before { service.stub(:items).and_return [] }
285
+ before do
286
+ Man.any_instance.stub(:save!){ fail }
287
+ Man.any_instance.stub(:errors).and_return({ base: "record_invalid" })
288
+ end
193
289
 
194
- it "вызывает исключение" do
195
- expect{ service.provide }.to raise_error
290
+ it "raises an exception" do
291
+ expect{ service.provide validate: false }.to raise_error
292
+ end
293
+
294
+ it "doesn't make any change to db" do
295
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Lord.all.to_a }
296
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Domain.all.to_a }
297
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Man.all.to_a }
298
+ end
299
+
300
+ it "adds corresponding errors to the #errors" do
301
+ begin; service.provide validate: false; rescue; end
302
+ service.errors.should_not be_blank
303
+ end
196
304
  end
197
305
 
198
- it "добавляет ошибки в массив" do
199
- begin; service.provide; rescue; end
200
- service.errors.should_not be_blank
306
+ context "and merged object's delete fails:" do
307
+
308
+ before do
309
+ Lord.any_instance.stub(:delete){ fail }
310
+ Lord.any_instance.stub(:errors).and_return({ base: "record_invalid" })
311
+ end
312
+
313
+ it "raises an exception" do
314
+ expect{ service.provide validate: false }.to raise_error
315
+ end
316
+
317
+ it "doesn't make any change to db" do
318
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Lord.all.to_a }
319
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Domain.all.to_a }
320
+ expect{ begin; service.provide validate: false; rescue; end }.not_to change{ Man.all.to_a }
321
+ end
322
+
323
+ it "adds corresponding errors to the #errors" do
324
+ begin; service.provide validate: false; rescue; end
325
+ service.errors.should_not be_blank
326
+ end
201
327
  end
202
328
  end
203
329
  end
@@ -9,11 +9,15 @@ describe ActiveMerge do
9
9
 
10
10
  let!(:lords) { 3.times.map{ Lord.create! }}
11
11
 
12
- it "доступен" do
12
+ it "defined" do
13
13
  Lord.should respond_to :merge_all
14
14
  end
15
15
 
16
- it "объединяет записи указанного запроса" do
16
+ it "allows options" do
17
+ Lord.should respond_to(:merge_all).with(1).argument
18
+ end
19
+
20
+ it "merges records from given request" do
17
21
  Lord.where("id < 3").merge_all
18
22
  Lord.all.pluck(:id).should eq [1, 3]
19
23
  end
Binary file