deferring 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 817f36897a24bc0726ce52d33dfc118591fc18da
4
- data.tar.gz: 6313e1831bf0294321b30daf3933da1891429603
3
+ metadata.gz: 9640c37fd475fa2857be6686a2f2b726a4f6a6ef
4
+ data.tar.gz: dfd12c320ff1fdcd8f2331a6b3180c473a894524
5
5
  SHA512:
6
- metadata.gz: 8999de2bd86c4621d82d658b0168339aa0ba42cdd4252be88047e5248ef4d5ac3ac7c85499479a2338c23816a529add87cd613a76e032c57d7e7669dac977561
7
- data.tar.gz: 5a9ccdc63b1a1c9fa4d1c218ed7343b9c0f2f9b4ccc0609da86c587f08235c42c64f2060d6461127ff2572740762830ec1379b4e9c1af5f8f958e5710c619597
6
+ metadata.gz: b8b85bcb7252d0af7f901ea97db87b1b0556ab3061f43d8dd9fa37b5dcc431cd59878a4dd0300571b241036f072a06d6a17d26db6374c0ce30712b2455952844
7
+ data.tar.gz: a614b0996a14b2ba60b5faa317e9f1d481685442c333dcb459b87f7240fc8b3e8df2a91c237188615a82fd5dcfca4fe62def66ca7ba05afe1ca57e90135f48bb
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- deferring (0.1.4)
4
+ deferring (0.2.0)
5
5
  activerecord (> 3.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- deferring (0.1.4)
4
+ deferring (0.2.0)
5
5
  activerecord (> 3.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- deferring (0.1.4)
4
+ deferring (0.2.0)
5
5
  activerecord (> 3.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- deferring (0.1.4)
4
+ deferring (0.2.0)
5
5
  activerecord (> 3.0)
6
6
 
7
7
  GEM
data/lib/deferring.rb CHANGED
@@ -21,6 +21,7 @@ module Deferring
21
21
  args.first.to_s,
22
22
  listeners,
23
23
  autosave: autosave,
24
+ type: :habtm,
24
25
  validate: validate)
25
26
  end
26
27
 
@@ -42,6 +43,7 @@ module Deferring
42
43
  inverse_association_name: inverse_association_name,
43
44
  autosave: autosave,
44
45
  type: :has_many,
46
+ dependent: options[:dependent],
45
47
  validate: validate)
46
48
  end
47
49
 
@@ -136,8 +138,9 @@ module Deferring
136
138
  def generate_deferred_association_methods(association_name, listeners, options = {})
137
139
  inverse_association_name = options[:inverse_association_name]
138
140
  autosave = options.fetch(:autosave, true)
139
- type = options.fetch(:type, :habtm)
141
+ type = options.fetch(:type)
140
142
  validate = options.fetch(:validate, true)
143
+ dependent = options[:dependent]
141
144
 
142
145
  # Store the original accessor methods of the association.
143
146
  alias_method :"original_#{association_name}", :"#{association_name}"
@@ -152,7 +155,7 @@ module Deferring
152
155
  # if none are found.
153
156
  # TODO: add force_reload argument?
154
157
  define_method :"#{association_name}" do
155
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
158
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
156
159
  send(:"deferred_#{association_name}")
157
160
  end
158
161
 
@@ -161,7 +164,7 @@ module Deferring
161
164
  # Replaces the collection's content by deleting and adding objects as
162
165
  # appropriate.
163
166
  define_method :"#{association_name}=" do |objects|
164
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
167
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
165
168
  send(:"deferred_#{association_name}").objects = objects
166
169
  end
167
170
 
@@ -170,7 +173,7 @@ module Deferring
170
173
  # Replace the collection by the objects identified by the primary keys in
171
174
  # ids.
172
175
  define_method :"#{association_name.singularize}_ids=" do |ids|
173
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
176
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
174
177
 
175
178
  ids ||= []
176
179
  klass = self.class.reflect_on_association(:"#{association_name}").klass
@@ -183,7 +186,7 @@ module Deferring
183
186
  #
184
187
  # Returns an array of the associated objects' ids.
185
188
  define_method :"#{association_name.singularize}_ids" do
186
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
189
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
187
190
  send(:"deferred_#{association_name}").ids
188
191
  end
189
192
 
@@ -197,7 +200,7 @@ module Deferring
197
200
 
198
201
  after_validation :"perform_deferred_#{association_name}_validation!"
199
202
  define_method :"perform_deferred_#{association_name}_validation!" do
200
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
203
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
201
204
 
202
205
  # Do not perform validations for HABTM associations as they are always
203
206
  # validated by Rails upon saving.
@@ -233,21 +236,21 @@ module Deferring
233
236
  # the save after the parent object has been saved
234
237
  after_save :"perform_deferred_#{association_name}_save!"
235
238
  define_method :"perform_deferred_#{association_name}_save!" do
236
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
239
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
237
240
 
238
241
  # Send the objects of our delegated association to the original
239
242
  # association and store the result.
240
243
  send(:"original_#{association_name}=", send(:"deferred_#{association_name}").objects)
241
244
 
242
245
  # Store the new value of the association into our delegated association.
243
- update_deferred_association(association_name, listeners, inverse_association_name)
246
+ update_deferred_association(association_name, listeners, inverse_association_name, dependent)
244
247
  end
245
248
 
246
249
  define_method :"reload_with_deferred_#{association_name}" do |*args|
247
- find_or_create_deferred_association(association_name, listeners, inverse_association_name)
250
+ find_or_create_deferred_association(association_name, listeners, inverse_association_name, dependent)
248
251
 
249
252
  send(:"reload_without_deferred_#{association_name}", *args).tap do
250
- update_deferred_association(association_name, listeners, inverse_association_name)
253
+ update_deferred_association(association_name, listeners, inverse_association_name, dependent)
251
254
  end
252
255
  end
253
256
  alias_method_chain :reload, :"deferred_#{association_name}"
@@ -257,11 +260,11 @@ module Deferring
257
260
  end
258
261
 
259
262
  def generate_update_deferred_assocation_method
260
- define_method :update_deferred_association do |name, listeners, inverse_association_name|
263
+ define_method :update_deferred_association do |name, listeners, inverse_association_name, dependent|
261
264
  klass = self.class.reflect_on_association(:"#{name}").klass
262
265
  send(
263
266
  :"deferred_#{name}=",
264
- DeferredAssociation.new(send(:"original_#{name}"), klass, self, inverse_association_name))
267
+ DeferredAssociation.new(send(:"original_#{name}"), klass, self, inverse_association_name, dependent))
265
268
  listeners.each do |event_name, callback_method|
266
269
  l = DeferredCallbackListener.new(event_name, self, callback_method)
267
270
  send(:"deferred_#{name}").add_callback_listener(l)
@@ -270,9 +273,9 @@ module Deferring
270
273
  end
271
274
 
272
275
  def generate_find_or_create_deferred_association_method
273
- define_method :find_or_create_deferred_association do |name, listeners, inverse_association_name|
276
+ define_method :find_or_create_deferred_association do |name, listeners, inverse_association_name, dependent|
274
277
  if send(:"deferred_#{name}").nil?
275
- update_deferred_association(name, listeners, inverse_association_name)
278
+ update_deferred_association(name, listeners, inverse_association_name, dependent)
276
279
  end
277
280
  end
278
281
  end
@@ -7,14 +7,19 @@ module Deferring
7
7
  # TODO: Write tests for enumerable.
8
8
  include Enumerable
9
9
 
10
- attr_reader :load_state, :klass, :parent_record, :inverse_name
10
+ attr_reader :load_state,
11
+ :klass,
12
+ :parent_record,
13
+ :inverse_name,
14
+ :dependent
11
15
 
12
- def initialize(original_association, klass, parent_record, inverse_name)
16
+ def initialize(original_association, klass, parent_record, inverse_name, dependent)
13
17
  super(original_association)
14
18
  @load_state = :ghost
15
19
  @klass = klass
16
20
  @parent_record = parent_record
17
21
  @inverse_name = inverse_name
22
+ @dependent = dependent
18
23
  end
19
24
  alias_method :original_association, :__getobj__
20
25
 
@@ -101,10 +106,10 @@ module Deferring
101
106
  objects.map(&:id)
102
107
  end
103
108
 
104
- def <<(records)
109
+ def <<(*records)
105
110
  # TODO: Do we want to prevent including the same object twice? Not sure,
106
111
  # but it will probably be filtered after saving and retrieving as well.
107
- Array(records).flatten.uniq.each do |record|
112
+ records.flatten.uniq.each do |record|
108
113
  run_deferring_callbacks(:link, record) do
109
114
  if inverse_name && record.class.reflect_on_association(inverse_name)
110
115
  record.send(:"#{inverse_name}=", parent_record)
@@ -119,13 +124,25 @@ module Deferring
119
124
  alias_method :concat, :<<
120
125
  alias_method :append, :<<
121
126
 
122
- def delete(records)
123
- Array(records).flatten.uniq.each do |record|
127
+ def delete(*records)
128
+ records.flatten.uniq.each do |record|
124
129
  run_deferring_callbacks(:unlink, record) { objects.delete(record) }
125
130
  end
126
131
  self
127
132
  end
128
133
 
134
+ def destroy(*records)
135
+ records.flatten.uniq.each do |record|
136
+ record = record.to_i if record.is_a? String
137
+ record = objects.detect { |o| o.id == record } if record.is_a? Fixnum
138
+
139
+ run_deferring_callbacks(:unlink, record) {
140
+ objects.delete(record)
141
+ record.mark_for_destruction if dependent && [:destroy, :delete_all].include?(dependent)
142
+ }
143
+ end
144
+ end
145
+
129
146
  def build(*args, &block)
130
147
  klass.new(*args, &block).tap do |record|
131
148
  run_deferring_callbacks(:link, record) do
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Deferring
4
- VERSION = '0.1.5'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -447,14 +447,14 @@ RSpec.describe 'deferred has_and_belongs_to_many associations' do
447
447
  ])
448
448
  end
449
449
 
450
- it 'only calls the rails callbacks when removing a record using destroy' do
450
+ it 'calls the unlink callbacks when removing a record using destroy' do
451
451
  bob = Person.where(name: 'Bob').first
452
- bob.teams.destroy(3)
452
+ bob.teams.destroy(Team.find(3))
453
453
 
454
454
  expect(bob.audit_log.length).to eq(2)
455
455
  expect(bob.audit_log).to eq([
456
- 'Before removing team 3',
457
- 'After removing team 3'
456
+ 'Before unlinking team 3',
457
+ 'After unlinking team 3'
458
458
  ])
459
459
  end
460
460
 
@@ -467,14 +467,19 @@ RSpec.describe 'deferred has_and_belongs_to_many associations' do
467
467
  bob.teams.delete(Team.find(1))
468
468
  bob.teams << Team.find(2)
469
469
  bob.teams.build(name: 'Service Desk')
470
+ bob.teams.destroy(Team.find(3))
470
471
  bob.save!
471
472
 
472
- expect(bob.audit_log.length).to eq(12)
473
+ expect(bob.audit_log.length).to eq(16)
473
474
  expect(bob.audit_log).to eq([
474
475
  'Before unlinking team 1', 'After unlinking team 1',
475
476
  'Before linking team 2', 'After linking team 2',
476
477
  'Before linking new team', 'After linking new team',
477
- 'Before removing team 1', 'After removing team 1',
478
+ 'Before unlinking team 3', 'After unlinking team 3',
479
+ 'Before removing team 3',
480
+ 'Before removing team 1',
481
+ 'After removing team 3',
482
+ 'After removing team 1',
478
483
  'Before adding team 2', 'After adding team 2',
479
484
  'Before adding new team', 'After adding team 4'
480
485
  ])
@@ -607,6 +612,96 @@ RSpec.describe 'deferred has_and_belongs_to_many associations' do
607
612
 
608
613
  end
609
614
 
615
+ describe '#destroy' do
616
+ context 'when called on has_many association with dependent: :delete_all' do
617
+ it 'destroys the records supplied and removes them from the collection' do
618
+ printer = Issue.create!(subject: 'Printer PRT-001 jammed')
619
+ database = Issue.create!(subject: 'Database server DB-1337 down')
620
+ sandwich = Issue.create!(subject: 'Make me a sandwich!')
621
+
622
+ bob.issues << printer << database << sandwich
623
+ bob.save!
624
+
625
+ expect {
626
+ bob.issues.destroy(printer)
627
+ bob.save!
628
+ }.to change {
629
+ Person.find(bob.id).issues.size
630
+ }.from(3).to(2)
631
+ expect { Issue.find(printer.id) }.to raise_error(ActiveRecord::RecordNotFound)
632
+ end
633
+ end
634
+
635
+ context 'when called on has_many association without dependent: :delete_all' do
636
+ it 'removes the records supplied from the collection' do
637
+ printer = Issue.create!(subject: 'Printer PRT-001 jammed')
638
+ database = Issue.create!(subject: 'Database server DB-1337 down')
639
+ sandwich = Issue.create!(subject: 'Make me a sandwich!')
640
+
641
+ bob.other_issues << printer << database << sandwich
642
+ bob.save!
643
+
644
+ expect {
645
+ bob.other_issues.destroy(printer)
646
+ bob.save!
647
+ }.to change {
648
+ Person.find(bob.id).other_issues.size
649
+ }.from(3).to(2)
650
+ expect(Issue.find(printer.id)).to eq(printer)
651
+ end
652
+ end
653
+
654
+ context 'when called on has_and_belongs_to_many association' do
655
+ it 'removes the records supplied from the collection' do
656
+ bob.teams << dba << operations
657
+ bob.save!
658
+
659
+ expect {
660
+ bob.teams.destroy(dba)
661
+ bob.save!
662
+ }.to change {
663
+ Person.find(bob.id).teams.size
664
+ }.from(2).to(1)
665
+ expect(Team.find(dba.id)).to eq(dba)
666
+ end
667
+ end
668
+
669
+ it 'returns an array with the removed records' do
670
+ printer = Issue.create!(subject: 'Printer PRT-001 jammed')
671
+ database = Issue.create!(subject: 'Database server DB-1337 down')
672
+ sandwich = Issue.create!(subject: 'Make me a sandwich!')
673
+
674
+ bob.issues << printer << database << sandwich
675
+ bob.save!
676
+
677
+ expect(bob.issues.destroy(database)).to eq([database])
678
+ end
679
+
680
+ it 'accepts Fixnum values' do
681
+ bob.teams << dba << operations
682
+ bob.save!
683
+
684
+ expect {
685
+ bob.teams.destroy(dba.id)
686
+ bob.save!
687
+ }.to change {
688
+ Person.find(bob.id).teams.size
689
+ }.from(2).to(1)
690
+ end
691
+
692
+ it 'accepts String values' do
693
+ bob.teams << dba << operations
694
+ bob.save!
695
+
696
+ expect {
697
+ bob.teams.destroy("#{dba.id}", "#{operations.id}")
698
+ bob.save!
699
+ }.to change {
700
+ Person.find(bob.id).teams.size
701
+ }.from(2).to(0)
702
+ end
703
+ end
704
+
610
705
  it 'should allow ActiveRecord::QueryMethods' do
611
706
  p = Person.first
612
707
  p.teams << dba << operations
@@ -12,9 +12,16 @@ class Person < ActiveRecord::Base
12
12
  deferred_accepts_nested_attributes_for :teams, allow_destroy: true
13
13
 
14
14
  deferred_has_many :issues, before_remove: :remove_issue,
15
- after_remove: :removed_issue
15
+ after_remove: :removed_issue,
16
+ dependent: :delete_all
16
17
  deferred_accepts_nested_attributes_for :issues, allow_destroy: true
17
18
 
19
+ # has_many without dependent: :delete_all, calling destroy on this association
20
+ # will not destroy the the Issue record
21
+ deferred_has_many :other_issues, before_remove: :remove_issue,
22
+ after_remove: :removed_issue,
23
+ class_name: 'Issue'
24
+
18
25
  deferred_has_many :non_validated_issues, before_remove: :remove_issue,
19
26
  after_remove: :removed_issue,
20
27
  validate: false
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deferring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robin Roestenburg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-07 00:00:00.000000000 Z
11
+ date: 2015-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord