hyper-model 1.0.alpha1.4 → 1.0.alpha1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/active_record_base.rb +1 -1
- data/lib/hyper-model.rb +1 -0
- data/lib/hyper_model/version.rb +1 -1
- data/lib/hyper_react/input_tags.rb +2 -1
- data/lib/reactive_record/active_record/associations.rb +117 -32
- data/lib/reactive_record/active_record/class_methods.rb +68 -14
- data/lib/reactive_record/active_record/error.rb +2 -0
- data/lib/reactive_record/active_record/errors.rb +8 -4
- data/lib/reactive_record/active_record/instance_methods.rb +22 -1
- data/lib/reactive_record/active_record/reactive_record/backing_record_inspector.rb +4 -4
- data/lib/reactive_record/active_record/reactive_record/base.rb +16 -5
- data/lib/reactive_record/active_record/reactive_record/collection.rb +53 -29
- data/lib/reactive_record/active_record/reactive_record/dummy_polymorph.rb +22 -0
- data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +1 -0
- data/lib/reactive_record/active_record/reactive_record/getters.rb +19 -7
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +28 -11
- data/lib/reactive_record/active_record/reactive_record/lookup_tables.rb +5 -5
- data/lib/reactive_record/active_record/reactive_record/setters.rb +104 -66
- data/lib/reactive_record/broadcast.rb +19 -9
- data/lib/reactive_record/interval.rb +3 -3
- data/lib/reactive_record/scope_description.rb +3 -2
- data/lib/reactive_record/server_data_cache.rb +12 -3
- data/polymorph-notes.md +143 -0
- metadata +9 -7
@@ -4,11 +4,11 @@ module ReactiveRecord
|
|
4
4
|
# the appropriate string. The order of execution is important!
|
5
5
|
module BackingRecordInspector
|
6
6
|
def inspection_details
|
7
|
-
return error_details
|
8
|
-
return new_details
|
7
|
+
return error_details unless errors.empty?
|
8
|
+
return new_details if new?
|
9
9
|
return destroyed_details if destroyed
|
10
|
-
return loading_details
|
11
|
-
return dirty_details
|
10
|
+
return loading_details unless @attributes.key? primary_key
|
11
|
+
return dirty_details unless changed_attributes.empty?
|
12
12
|
"[loaded id: #{id}]"
|
13
13
|
end
|
14
14
|
|
@@ -71,7 +71,7 @@ module ReactiveRecord
|
|
71
71
|
if (id_to_find = attrs[model.primary_key])
|
72
72
|
!new_only && lookup_by_id(model, id_to_find)
|
73
73
|
else
|
74
|
-
@records[model].detect do |r|
|
74
|
+
@records[model.base_class].detect do |r|
|
75
75
|
(r.new? || !new_only) &&
|
76
76
|
!attrs.detect { |attr, value| r.synced_attributes[attr] != value }
|
77
77
|
end
|
@@ -118,6 +118,9 @@ module ReactiveRecord
|
|
118
118
|
# this is the equivilent of find but for associations and aggregations
|
119
119
|
# because we are not fetching a specific attribute yet, there is NO communication with the
|
120
120
|
# server. That only happens during find.
|
121
|
+
|
122
|
+
return DummyPolymorph.new(vector) unless model
|
123
|
+
|
121
124
|
model = model.base_class
|
122
125
|
|
123
126
|
# do we already have a record with this vector? If so return it, otherwise make a new one.
|
@@ -147,7 +150,7 @@ module ReactiveRecord
|
|
147
150
|
@attributes = {}
|
148
151
|
@changed_attributes = []
|
149
152
|
@virgin = true
|
150
|
-
records[model] << self
|
153
|
+
records[model.base_class] << self
|
151
154
|
Base.set_object_id_lookup(self)
|
152
155
|
end
|
153
156
|
|
@@ -204,7 +207,7 @@ module ReactiveRecord
|
|
204
207
|
end
|
205
208
|
|
206
209
|
def errors
|
207
|
-
@errors ||= ActiveModel::Errors.new(
|
210
|
+
@errors ||= ActiveModel::Errors.new(ar_instance)
|
208
211
|
end
|
209
212
|
|
210
213
|
# called when we have a newly created record, to initialize
|
@@ -250,7 +253,7 @@ module ReactiveRecord
|
|
250
253
|
return if @create_sync
|
251
254
|
@create_sync = true
|
252
255
|
end
|
253
|
-
model.unscoped
|
256
|
+
model.unscoped._internal_push ar_instance
|
254
257
|
@synced_with_unscoped = !@synced_with_unscoped
|
255
258
|
end
|
256
259
|
|
@@ -307,9 +310,11 @@ module ReactiveRecord
|
|
307
310
|
@saving = true
|
308
311
|
end
|
309
312
|
|
310
|
-
def errors!(hash)
|
313
|
+
def errors!(hash, saving)
|
314
|
+
@errors_at_last_sync = hash if saving
|
311
315
|
notify_waiting_for_save
|
312
316
|
errors.clear && return unless hash
|
317
|
+
errors.non_reactive_clear
|
313
318
|
hash.each do |attribute, messages|
|
314
319
|
messages.each do |message|
|
315
320
|
errors.add(attribute, message)
|
@@ -317,6 +322,11 @@ module ReactiveRecord
|
|
317
322
|
end
|
318
323
|
end
|
319
324
|
|
325
|
+
def revert_errors!
|
326
|
+
puts "#{inspect}.revert_errors! @errors_at_last_sync: #{@errors_at_last_sync}"
|
327
|
+
errors!(@errors_at_last_sync)
|
328
|
+
end
|
329
|
+
|
320
330
|
def saved!(save_only = nil) # sets saving to false AND notifies
|
321
331
|
notify_waiting_for_save
|
322
332
|
return self if save_only
|
@@ -418,6 +428,7 @@ module ReactiveRecord
|
|
418
428
|
|
419
429
|
def destroy_associations
|
420
430
|
@destroyed = false
|
431
|
+
@being_destroyed = true
|
421
432
|
model.reflect_on_all_associations.each do |association|
|
422
433
|
if association.collection?
|
423
434
|
@attributes[association.attribute].replace([]) if @attributes[association.attribute]
|
@@ -77,6 +77,8 @@ module ReactiveRecord
|
|
77
77
|
(@collection.length..index).each do |i|
|
78
78
|
new_dummy_record = ReactiveRecord::Base.new_from_vector(@target_klass, nil, *@vector, "*#{i}")
|
79
79
|
new_dummy_record.attributes[@association.inverse_of] = @owner if @association && !@association.through_association?
|
80
|
+
# HMT-TODO: the above needs to be looked into... if we are a hmt then don't we need to create a dummy on the joins collection as well?
|
81
|
+
# or maybe this just does not work for HMT?
|
80
82
|
@collection << new_dummy_record
|
81
83
|
end
|
82
84
|
end
|
@@ -212,7 +214,7 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
212
214
|
return [] unless attrs[@association.inverse_of] == @owner
|
213
215
|
if !@association.through_association
|
214
216
|
[record]
|
215
|
-
elsif (source = attrs[@association.source])
|
217
|
+
elsif (source = attrs[@association.source]) && source.is_a?(@target_klass)
|
216
218
|
[source]
|
217
219
|
else
|
218
220
|
[]
|
@@ -233,7 +235,8 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
233
235
|
end
|
234
236
|
|
235
237
|
def in_this_collection(related_records)
|
236
|
-
|
238
|
+
# HMT-TODO: I don't think we can get a set of related records here with a through association unless they are part of the collection
|
239
|
+
return related_records if !@association || @association.through_association?
|
237
240
|
related_records.select do |r|
|
238
241
|
r.backing_record.attributes[@association.inverse_of] == @owner
|
239
242
|
end
|
@@ -406,7 +409,11 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
406
409
|
def set_belongs_to(child)
|
407
410
|
if @owner
|
408
411
|
# TODO this is major broken...current
|
409
|
-
|
412
|
+
if (through_association = @association.through_association)
|
413
|
+
# HMT-TODO: create a new record with owner and child
|
414
|
+
else
|
415
|
+
child.send("#{@association.inverse_of}=", @owner) if @association && !@association.through_association
|
416
|
+
end
|
410
417
|
elsif @parent
|
411
418
|
@parent.set_belongs_to(child)
|
412
419
|
end
|
@@ -421,19 +428,40 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
421
428
|
|
422
429
|
def update_child(item)
|
423
430
|
backing_record = item.backing_record
|
424
|
-
|
431
|
+
# HMT TODO: The following && !association.through_association was commented out, causing wrong class items to be added to
|
432
|
+
# associations
|
433
|
+
# Why was it commented out.
|
434
|
+
if backing_record && @owner && @association && item.attributes[@association.inverse_of] != @owner && !@association.through_association?
|
425
435
|
inverse_of = @association.inverse_of
|
426
|
-
|
436
|
+
current_association_value = item.attributes[inverse_of]
|
427
437
|
backing_record.virgin = false unless backing_record.data_loading?
|
438
|
+
# next line was commented out and following line was active.
|
428
439
|
backing_record.update_belongs_to(inverse_of, @owner)
|
429
|
-
|
430
|
-
|
431
|
-
|
440
|
+
#backing_record.set_belongs_to_via_has_many(@association, @owner)
|
441
|
+
# following is handled by update_belongs_to and is redundant
|
442
|
+
# unless current_association_value.nil? # might be a dummy value which responds to nil
|
443
|
+
# current_association = @association.inverse.inverse(current_association_value)
|
444
|
+
# current_association_attribute = current_association.attribute
|
445
|
+
# if current_association.collection? && current_association_value.attributes[current_association_attribute]
|
446
|
+
# current_association.attributes[current_association_attribute].delete(item)
|
447
|
+
# end
|
448
|
+
# end
|
432
449
|
@owner.backing_record.sync_has_many(@association.attribute)
|
433
450
|
end
|
434
451
|
end
|
435
452
|
|
436
453
|
def push(item)
|
454
|
+
if (through_association = @association&.through_association)
|
455
|
+
through_association.klass.create(@association.inverse_of => @owner, @association.source => item)
|
456
|
+
self
|
457
|
+
else
|
458
|
+
_internal_push(item)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
alias << push
|
463
|
+
|
464
|
+
def _internal_push(item)
|
437
465
|
item.itself # force get of at least the id
|
438
466
|
if collection
|
439
467
|
self.force_push item
|
@@ -449,8 +477,6 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
449
477
|
self
|
450
478
|
end
|
451
479
|
|
452
|
-
alias << push
|
453
|
-
|
454
480
|
def sort!(*args, &block)
|
455
481
|
replace(sort(*args, &block))
|
456
482
|
end
|
@@ -514,19 +540,19 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
514
540
|
@dummy_collection.notify
|
515
541
|
array = new_array.is_a?(Collection) ? new_array.collection : new_array
|
516
542
|
@collection.each_with_index do |r, i|
|
517
|
-
r.id = new_array[i].id if array[i] and array[i].id and !r.
|
543
|
+
r.id = new_array[i].id if array[i] and array[i].id and !r.new_record? and r.backing_record.vector.last =~ /^\*[0-9]+$/
|
518
544
|
end
|
519
545
|
end
|
520
|
-
|
521
|
-
@collection.dup.each { |item| delete(item) } if @collection
|
546
|
+
# the following makes sure that the existing elements are properly removed from the collection
|
547
|
+
@collection.dup.each { |item| delete(item) } if @collection
|
522
548
|
@collection = []
|
523
549
|
if new_array.is_a? Collection
|
524
550
|
@dummy_collection = new_array.dummy_collection
|
525
551
|
@dummy_record = new_array.dummy_record
|
526
|
-
new_array.collection.each { |item|
|
552
|
+
new_array.collection.each { |item| _internal_push item } if new_array.collection
|
527
553
|
else
|
528
554
|
@dummy_collection = @dummy_record = nil
|
529
|
-
new_array.each { |item|
|
555
|
+
new_array.each { |item| _internal_push item }
|
530
556
|
end
|
531
557
|
notify_of_change new_array
|
532
558
|
end
|
@@ -534,9 +560,9 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
534
560
|
def delete(item)
|
535
561
|
unsaved_children.delete(item)
|
536
562
|
notify_of_change(
|
537
|
-
if @owner && @association
|
563
|
+
if @owner && @association
|
538
564
|
inverse_of = @association.inverse_of
|
539
|
-
if (backing_record = item.backing_record) && item.attributes[inverse_of] == @owner
|
565
|
+
if (backing_record = item.backing_record) && item.attributes[inverse_of] == @owner && !@association.through_association?
|
540
566
|
# the if prevents double update if delete is being called from << (see << above)
|
541
567
|
backing_record.update_belongs_to(inverse_of, nil)
|
542
568
|
end
|
@@ -562,20 +588,8 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
562
588
|
@dummy_collection.loading?
|
563
589
|
end
|
564
590
|
|
565
|
-
def loaded?
|
566
|
-
false && @collection && (!@dummy_collection || !@dummy_collection.loading?) && (!@owner || @owner.id || @vector.length > 1)
|
567
|
-
end
|
568
|
-
|
569
|
-
def empty?
|
570
|
-
# should be handled by method missing below, but opal-rspec does not deal well
|
571
|
-
# with method missing, so to test...
|
572
|
-
all.empty?
|
573
|
-
end
|
574
|
-
|
575
591
|
def find_by(attrs)
|
576
592
|
attrs = @target_klass.__hyperstack_preprocess_attrs(attrs)
|
577
|
-
# r = @collection&.detect { |lr| lr.new_record? && !attrs.detect { |k, v| lr.attributes[k] != v } }
|
578
|
-
# return r if r
|
579
593
|
(r = __hyperstack_internal_scoped_find_by(attrs)) || return
|
580
594
|
r.backing_record.sync_attributes(attrs).set_ar_instance!
|
581
595
|
end
|
@@ -596,6 +610,16 @@ To determine this sync_scopes first asks if the record being changed is in the s
|
|
596
610
|
found
|
597
611
|
end
|
598
612
|
|
613
|
+
# to avoid fetching the entire collection array we check empty and any against the count
|
614
|
+
|
615
|
+
def empty?
|
616
|
+
count.zero?
|
617
|
+
end
|
618
|
+
|
619
|
+
def any?
|
620
|
+
!count.zero?
|
621
|
+
end
|
622
|
+
|
599
623
|
def method_missing(method, *args, &block)
|
600
624
|
if args.count == 1 && method.start_with?('find_by_')
|
601
625
|
find_by(method.sub(/^find_by_/, '') => args[0])
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ReactiveRecord
|
2
|
+
class DummyPolymorph
|
3
|
+
def initialize(vector)
|
4
|
+
@vector = vector
|
5
|
+
puts "VECTOR: #{@vector.inspect}"
|
6
|
+
Base.load_from_db(nil, *vector, 'id')
|
7
|
+
Base.load_from_db(nil, *vector, 'model_name')
|
8
|
+
end
|
9
|
+
|
10
|
+
def nil?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(*)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.reflect_on_all_associations(*)
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,9 +4,13 @@ module ReactiveRecord
|
|
4
4
|
module Getters
|
5
5
|
def get_belongs_to(assoc, reload = nil)
|
6
6
|
getter_common(assoc.attribute, reload) do |has_key, attr|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
next if new?
|
8
|
+
if id.present?
|
9
|
+
value = fetch_by_id(attr, @model.primary_key)
|
10
|
+
klass = fetch_by_id(attr, 'model_name')
|
11
|
+
klass &&= Object.const_get(klass)
|
12
|
+
end
|
13
|
+
value = find_association(assoc, value, klass)
|
10
14
|
sync_ignore_dummy attr, value, has_key
|
11
15
|
end&.cast_to_current_sti_type
|
12
16
|
end
|
@@ -104,18 +108,26 @@ module ReactiveRecord
|
|
104
108
|
else
|
105
109
|
virtual_fetch_on_server_warning(attribute) if on_opal_server? && changed?
|
106
110
|
yield false, attribute
|
107
|
-
end.tap {
|
111
|
+
end.tap { Hyperstack::Internal::State::Variable.get(self, attribute) unless data_loading? }
|
108
112
|
end
|
109
113
|
|
110
|
-
def find_association(association, id)
|
111
|
-
inverse_of = association.inverse_of
|
114
|
+
def find_association(association, id, klass)
|
112
115
|
instance = if id
|
113
|
-
find(
|
116
|
+
find(klass, klass.primary_key => id)
|
117
|
+
elsif association.polymorphic?
|
118
|
+
new_from_vector(nil, nil, *vector, association.attribute)
|
114
119
|
else
|
115
120
|
new_from_vector(association.klass, nil, *vector, association.attribute)
|
116
121
|
end
|
122
|
+
return instance if instance.is_a? DummyPolymorph
|
123
|
+
inverse_of = association.inverse_of(instance)
|
117
124
|
instance_backing_record_attributes = instance.attributes
|
118
125
|
inverse_association = association.klass.reflect_on_association(inverse_of)
|
126
|
+
# HMT-TODO: don't we need to do something with the through association case.
|
127
|
+
# perhaps we never hit this point...
|
128
|
+
if association.through_association?
|
129
|
+
IsomorphicHelpers.log "*********** called #{ar_instance}.find_association(#{association.attribute}) which is has many through!!!!!!!", :error
|
130
|
+
end
|
119
131
|
if inverse_association.collection?
|
120
132
|
instance_backing_record_attributes[inverse_of] = if id and id != ""
|
121
133
|
Collection.new(@model, instance, inverse_association, association.klass, ["find", id], inverse_of)
|
@@ -135,7 +135,6 @@ module ReactiveRecord
|
|
135
135
|
model.columns_hash[method_name] || model.server_methods[method_name]
|
136
136
|
end
|
137
137
|
|
138
|
-
|
139
138
|
class << self
|
140
139
|
|
141
140
|
attr_reader :pending_fetches
|
@@ -234,7 +233,7 @@ module ReactiveRecord
|
|
234
233
|
if association.collection?
|
235
234
|
# following line changed from .all to .collection on 10/28
|
236
235
|
[*value.collection, *value.unsaved_children].each do |assoc|
|
237
|
-
add_new_association.call(record, attribute, assoc.backing_record) if assoc.changed?(association.inverse_of) or assoc.
|
236
|
+
add_new_association.call(record, attribute, assoc.backing_record) if assoc.changed?(association.inverse_of(assoc)) or assoc.new_record?
|
238
237
|
end
|
239
238
|
elsif record.new? || record.changed?(attribute) || (record == record_being_saved && force)
|
240
239
|
if value.nil?
|
@@ -243,7 +242,7 @@ module ReactiveRecord
|
|
243
242
|
add_new_association.call record, attribute, value.backing_record
|
244
243
|
end
|
245
244
|
end
|
246
|
-
elsif aggregation = record.model.reflect_on_aggregation(attribute)
|
245
|
+
elsif (aggregation = record.model.reflect_on_aggregation(attribute)) && (aggregation.klass < ActiveRecord::Base)
|
247
246
|
add_new_association.call record, attribute, value.backing_record unless value.nil?
|
248
247
|
elsif aggregation
|
249
248
|
new_value = aggregation.serialize(value)
|
@@ -264,8 +263,17 @@ module ReactiveRecord
|
|
264
263
|
HyperMesh.load do
|
265
264
|
ReactiveRecord.loads_pending! unless self.class.pending_fetches.empty?
|
266
265
|
end.then { send_save_to_server(save, validate, force, &block) }
|
267
|
-
#save_to_server(validate, force, &block)
|
268
266
|
else
|
267
|
+
if validate
|
268
|
+
# Handles the case where a model is valid, then some attribute is
|
269
|
+
# updated, and model.validate is called updating the error data.
|
270
|
+
# Now lets say the attribute changes back to the last synced value. In
|
271
|
+
# this case we need to revert the error records.
|
272
|
+
models, _, backing_records = self.class.gather_records([self], true, self)
|
273
|
+
models.each do |item|
|
274
|
+
backing_records[item[:id]].revert_errors!
|
275
|
+
end
|
276
|
+
end
|
269
277
|
promise = Promise.new
|
270
278
|
yield true, nil, [] if block
|
271
279
|
promise.resolve({success: true})
|
@@ -302,14 +310,13 @@ module ReactiveRecord
|
|
302
310
|
|
303
311
|
response[:saved_models].each do | item |
|
304
312
|
backing_records[item[0]].sync_unscoped_collection! if save
|
305
|
-
backing_records[item[0]].errors! item[3]
|
313
|
+
backing_records[item[0]].errors! item[3], save
|
306
314
|
end
|
307
315
|
|
308
316
|
yield response[:success], response[:message], response[:models] if block
|
309
317
|
promise.resolve response # TODO this could be problematic... there was no .json here, so .... what's to do?
|
310
318
|
|
311
319
|
rescue Exception => e
|
312
|
-
# debugger
|
313
320
|
log("Exception raised while saving - #{e}", :error)
|
314
321
|
ensure
|
315
322
|
backing_records.each { |_id, record| record.saved! rescue nil } if save
|
@@ -454,6 +461,11 @@ module ReactiveRecord
|
|
454
461
|
elsif parent.class.reflect_on_association(association[:attribute].to_sym).collection?
|
455
462
|
#puts ">>>>>>>>>> #{parent.class.name}.send('#{association[:attribute]}') << #{reactive_records[association[:child_id]]})"
|
456
463
|
dont_save_list.delete(parent)
|
464
|
+
|
465
|
+
|
466
|
+
# if reactive_records[association[:child_id]]&.new_record?
|
467
|
+
# dont_save_list << reactive_records[association[:child_id]]
|
468
|
+
# end
|
457
469
|
#if false and parent.new?
|
458
470
|
#parent.send("#{association[:attribute]}") << reactive_records[association[:child_id]]
|
459
471
|
# puts "updated"
|
@@ -464,10 +476,13 @@ module ReactiveRecord
|
|
464
476
|
#puts ">>>>ASSOCIATION>>>> #{parent.class.name}.send('#{association[:attribute]}=', #{reactive_records[association[:child_id]]})"
|
465
477
|
parent.send("#{association[:attribute]}=", reactive_records[association[:child_id]])
|
466
478
|
dont_save_list.delete(parent)
|
467
|
-
|
479
|
+
|
480
|
+
# if parent.class.reflect_on_association(association[:attribute].to_sym).macro == :has_one &&
|
481
|
+
# reactive_records[association[:child_id]]&.new_record?
|
482
|
+
# dont_save_list << reactive_records[association[:child_id]]
|
483
|
+
# end
|
468
484
|
end
|
469
485
|
end if associations
|
470
|
-
|
471
486
|
# get rid of any records that don't require further processing, as a side effect
|
472
487
|
# we also save any records that need to be saved (these may be rolled back later.)
|
473
488
|
|
@@ -476,7 +491,9 @@ module ReactiveRecord
|
|
476
491
|
next true if record.frozen? # skip (but process later) frozen records
|
477
492
|
next true if dont_save_list.include?(record) # skip if the record is on the don't save list
|
478
493
|
next true if record.changed.include?(record.class.primary_key) # happens on an aggregate
|
479
|
-
next
|
494
|
+
#next true if record.persisted? # record may be have been saved as result of has_one assignment
|
495
|
+
# next false if record.id && !record.changed? # throw out any existing records with no changes
|
496
|
+
next record.persisted? if record.id && !record.changed?
|
480
497
|
# if we get to here save the record and return true to keep it
|
481
498
|
op = new_models.include?(record) ? :create_permitted? : :update_permitted?
|
482
499
|
record.check_permission_with_acting_user(acting_user, op).save(validate: false) || true
|
@@ -492,14 +509,15 @@ module ReactiveRecord
|
|
492
509
|
# the all the error messages during a save so we can dump them to the server log.
|
493
510
|
|
494
511
|
all_messages = []
|
512
|
+
attributes = nil
|
495
513
|
|
496
514
|
saved_models = reactive_records.collect do |reactive_record_id, model|
|
497
515
|
messages = model.errors.messages if validate && !model.valid?
|
498
516
|
all_messages << [model, messages] if save && messages
|
499
517
|
attributes = model.__hyperstack_secure_attributes(acting_user)
|
518
|
+
attributes[model.class.primary_key] = model[model.class.primary_key]
|
500
519
|
[reactive_record_id, model.class.name, attributes, messages]
|
501
520
|
end
|
502
|
-
|
503
521
|
# if we are not saving (i.e. just validating) then we rollback the transaction
|
504
522
|
|
505
523
|
raise ActiveRecord::Rollback, 'This Rollback is intentional!' unless save
|
@@ -514,7 +532,6 @@ module ReactiveRecord
|
|
514
532
|
end
|
515
533
|
raise 'HyperModel saving records failed!'
|
516
534
|
end
|
517
|
-
|
518
535
|
end
|
519
536
|
|
520
537
|
{ success: true, saved_models: saved_models }
|