reactive-record 0.7.15 → 0.7.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/reactive_record/reactive_record_controller.rb +4 -4
- data/lib/reactive_record/active_record/class_methods.rb +4 -0
- data/lib/reactive_record/active_record/instance_methods.rb +30 -22
- data/lib/reactive_record/active_record/reactive_record/base.rb +69 -31
- data/lib/reactive_record/active_record/reactive_record/collection.rb +30 -20
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +55 -19
- data/lib/reactive_record/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 139439c144b766200fccb72d67240cbfec0d6eae
|
4
|
+
data.tar.gz: 1d67f45f99d68e4e2dd0ac5db2ee88885b491e80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4389f9eeecb8e5da8ff5788bdcb5886b2f086111e8a7ca7620e65e78cec26fcdb2b371fb2ab2d38fa0a7f3517a675478557a1a157915e99a93848e6d526b105d
|
7
|
+
data.tar.gz: 1c647b32c2b98182e8e8dbd12672ce1faca07bce3613405baec06c8c30ed56a21f15e27d342448fdd10969dddcd82b40d36acb04669693ea5116262b83969e63
|
@@ -3,16 +3,16 @@ require 'reactive_record/server_data_cache'
|
|
3
3
|
module ReactiveRecord
|
4
4
|
|
5
5
|
class ReactiveRecordController < ::ApplicationController
|
6
|
-
|
6
|
+
|
7
7
|
def fetch
|
8
8
|
render :json => ReactiveRecord::ServerDataCache[params[:pending_fetches], acting_user]
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
|
12
12
|
def save
|
13
|
-
render :json => ReactiveRecord::Base.save_records(params[:models], params[:associations], acting_user)
|
13
|
+
render :json => ReactiveRecord::Base.save_records(params[:models], params[:associations], acting_user, params[:validate])
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def destroy
|
17
17
|
render :json => ReactiveRecord::Base.destroy_record(params[:model], params[:id], params[:vector], acting_user)
|
18
18
|
end
|
@@ -90,6 +90,10 @@ module ActiveRecord
|
|
90
90
|
Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
|
91
91
|
end
|
92
92
|
|
93
|
+
def column_names
|
94
|
+
[] # it would be great to figure out how to get this information on the client! For now we just return an empty array
|
95
|
+
end
|
96
|
+
|
93
97
|
[
|
94
98
|
"table_name=", "before_validation", "with_options", "validates_presence_of", "validates_format_of",
|
95
99
|
"accepts_nested_attributes_for", "before_create", "after_create", "before_save", "after_save", "before_destroy", "where", "validate",
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
|
2
|
+
|
3
3
|
module InstanceMethods
|
4
|
-
|
4
|
+
|
5
5
|
def attributes
|
6
6
|
@backing_record.attributes
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def initialize(hash = {})
|
10
10
|
if hash.is_a? ReactiveRecord::Base
|
11
11
|
@backing_record = hash
|
@@ -14,19 +14,27 @@ module ActiveRecord
|
|
14
14
|
# we have to build the backing record first then initialize it so associations work correctly
|
15
15
|
@backing_record = ReactiveRecord::Base.new(self.class, {}, self)
|
16
16
|
@backing_record.instance_eval do
|
17
|
-
self.class.load_data
|
17
|
+
self.class.load_data do
|
18
|
+
hash.each do |attribute, value|
|
19
|
+
unless attribute == primary_key
|
20
|
+
reactive_set!(attribute, value) unless attribute == primary_key
|
21
|
+
changed_attributes << attribute
|
22
|
+
end
|
23
|
+
end
|
24
|
+
#changed_attributes << primary_key # insures that changed attributes has at least one element
|
25
|
+
end
|
18
26
|
end
|
19
27
|
end
|
20
28
|
end
|
21
|
-
|
29
|
+
|
22
30
|
def primary_key
|
23
31
|
self.class.primary_key
|
24
32
|
end
|
25
|
-
|
33
|
+
|
26
34
|
def id
|
27
35
|
@backing_record.reactive_get!(primary_key)
|
28
36
|
end
|
29
|
-
|
37
|
+
|
30
38
|
def id=(value)
|
31
39
|
@backing_record.id = value
|
32
40
|
end
|
@@ -35,19 +43,19 @@ module ActiveRecord
|
|
35
43
|
# in reality should return ActiveModel::Name object, blah blah
|
36
44
|
self.class.model_name
|
37
45
|
end
|
38
|
-
|
46
|
+
|
39
47
|
def revert
|
40
48
|
@backing_record.revert
|
41
49
|
end
|
42
|
-
|
50
|
+
|
43
51
|
def changed?
|
44
52
|
@backing_record.changed?
|
45
53
|
end
|
46
|
-
|
54
|
+
|
47
55
|
def ==(ar_instance)
|
48
56
|
@backing_record == ar_instance.instance_eval { @backing_record }
|
49
57
|
end
|
50
|
-
|
58
|
+
|
51
59
|
def method_missing(name, *args, &block)
|
52
60
|
if name =~ /_changed\?$/
|
53
61
|
@backing_record.changed?(name.gsub(/_changed\?$/,""))
|
@@ -55,33 +63,33 @@ module ActiveRecord
|
|
55
63
|
attribute_name = name.gsub(/=$/,"")
|
56
64
|
@backing_record.reactive_set!(attribute_name, args[0])
|
57
65
|
elsif args.count == 0 && !block
|
58
|
-
@backing_record.reactive_get!(name)
|
66
|
+
@backing_record.reactive_get!(name)
|
59
67
|
else
|
60
68
|
super
|
61
69
|
end
|
62
70
|
end
|
63
|
-
|
64
|
-
def save(&block)
|
65
|
-
@backing_record.save &block
|
71
|
+
|
72
|
+
def save(opts = {}, &block)
|
73
|
+
@backing_record.save(opts[:validate], &block)
|
66
74
|
end
|
67
|
-
|
75
|
+
|
68
76
|
def saving?
|
69
77
|
@backing_record.saving?
|
70
78
|
end
|
71
|
-
|
79
|
+
|
72
80
|
def destroy(&block)
|
73
81
|
@backing_record.destroy &block
|
74
82
|
end
|
75
|
-
|
83
|
+
|
76
84
|
def new?
|
77
85
|
@backing_record.new?
|
78
86
|
end
|
79
|
-
|
87
|
+
|
80
88
|
def errors
|
89
|
+
React::State.get_state(@backing_record, @backing_record)
|
81
90
|
@backing_record.errors
|
82
91
|
end
|
83
|
-
|
92
|
+
|
84
93
|
end
|
85
|
-
|
94
|
+
|
86
95
|
end
|
87
|
-
|
@@ -29,6 +29,9 @@ module ReactiveRecord
|
|
29
29
|
attr_accessor :ar_instance
|
30
30
|
attr_accessor :vector
|
31
31
|
attr_accessor :model
|
32
|
+
attr_accessor :changed_attributes
|
33
|
+
attr_accessor :aggregate_owner
|
34
|
+
attr_accessor :aggregate_attribute
|
32
35
|
|
33
36
|
# While data is being loaded from the server certain internal behaviors need to change
|
34
37
|
# for example records all record changes are synced as they happen.
|
@@ -84,7 +87,7 @@ module ReactiveRecord
|
|
84
87
|
record.ar_instance ||= infer_type_from_hash(model, record.attributes).new(record)
|
85
88
|
end
|
86
89
|
|
87
|
-
def self.new_from_vector(model,
|
90
|
+
def self.new_from_vector(model, aggregate_owner, *vector)
|
88
91
|
# this is the equivilent of find but for associations and aggregations
|
89
92
|
# because we are not fetching a specific attribute yet, there is NO communication with the
|
90
93
|
# server. That only happens during find.
|
@@ -97,6 +100,8 @@ module ReactiveRecord
|
|
97
100
|
record = new model
|
98
101
|
record.vector = vector
|
99
102
|
end
|
103
|
+
record.aggregate_owner = aggregate_owner
|
104
|
+
record.aggregate_attribute = vector.last
|
100
105
|
record.ar_instance ||= infer_type_from_hash(model, record.attributes).new(record)
|
101
106
|
end
|
102
107
|
|
@@ -105,6 +110,7 @@ module ReactiveRecord
|
|
105
110
|
@ar_instance = ar_instance
|
106
111
|
@synced_attributes = {}
|
107
112
|
@attributes = {}
|
113
|
+
@changed_attributes = []
|
108
114
|
records[model] << self
|
109
115
|
end
|
110
116
|
|
@@ -174,39 +180,54 @@ module ReactiveRecord
|
|
174
180
|
attributes[attribute].attributes[inverse_of] = nil
|
175
181
|
end
|
176
182
|
end
|
183
|
+
elsif @model.reflect_on_aggregation(attribute)
|
184
|
+
attributes[attribute].instance_variable_get(:@backing_record).aggregate_owner = nil if attributes[attribute]
|
185
|
+
aggregate = value.instance_variable_get(:@backing_record)
|
186
|
+
aggregate.aggregate_owner = self
|
187
|
+
aggregate.aggregate_attribute = attribute
|
177
188
|
end
|
178
|
-
|
179
|
-
attributes[attribute] = value
|
180
|
-
React::State.set_state(self, attribute, value) unless data_loading?
|
181
|
-
React::State.set_state(self, self, :changed) unless data_loading? or (was_changed == changed2({attribute => value}))
|
189
|
+
update_attribute(attribute, value)
|
182
190
|
end
|
183
191
|
value
|
184
192
|
end
|
185
193
|
|
186
|
-
def
|
187
|
-
|
188
|
-
|
189
|
-
@
|
194
|
+
def update_attribute(attribute, *args)
|
195
|
+
value = args[0]
|
196
|
+
changed = if args.count == 0
|
197
|
+
if association = @model.reflect_on_association(attribute) and association.collection?
|
198
|
+
attributes[attribute] != @synced_attributes[attribute]
|
199
|
+
else
|
200
|
+
!attributes[attribute].instance_variable_get(:@backing_record).changed_attributes.empty?
|
201
|
+
end
|
202
|
+
elsif association = @model.reflect_on_association(attribute) and association.collection?
|
203
|
+
value != @synced_attributes[attribute]
|
190
204
|
else
|
191
|
-
|
192
|
-
|
193
|
-
|
205
|
+
!@synced_attributes.has_key?(attribute) or @synced_attributes[attribute] != value
|
206
|
+
end
|
207
|
+
empty_before = changed_attributes.empty?
|
208
|
+
if !changed
|
209
|
+
changed_attributes.delete(attribute)
|
210
|
+
elsif !changed_attributes.include?(attribute)
|
211
|
+
changed_attributes << attribute
|
212
|
+
end
|
213
|
+
attributes[attribute] = value if args.count != 0
|
214
|
+
React::State.set_state(self, attribute, value) unless data_loading?
|
215
|
+
if empty_before != changed_attributes.empty?
|
216
|
+
React::State.set_state(self, "!CHANGED!", !changed_attributes.empty?) unless data_loading?
|
217
|
+
aggregate_owner.update_attribute(aggregate_attribute) if aggregate_owner
|
218
|
+
end
|
194
219
|
end
|
195
220
|
|
196
|
-
def
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
return true
|
204
|
-
end
|
221
|
+
def changed?(*args)
|
222
|
+
if args.count == 0
|
223
|
+
React::State.get_state(self, "!CHANGED!")
|
224
|
+
!changed_attributes.empty?
|
225
|
+
else
|
226
|
+
React::State.get_state(self, args[0])
|
227
|
+
changed_attributes.include? args[0]
|
205
228
|
end
|
206
|
-
false
|
207
229
|
end
|
208
230
|
|
209
|
-
|
210
231
|
def errors
|
211
232
|
@errors ||= ActiveModel::Error.new
|
212
233
|
end
|
@@ -214,15 +235,25 @@ module ReactiveRecord
|
|
214
235
|
def sync!(hash = {}) # does NOT notify (see saved! for notification)
|
215
236
|
@attributes.merge! hash
|
216
237
|
@synced_attributes = @attributes.dup
|
217
|
-
@synced_attributes.each
|
238
|
+
@synced_attributes.each do |key, value|
|
239
|
+
if value.is_a? Collection
|
240
|
+
@synced_attributes[key] = value.dup_for_sync
|
241
|
+
elsif aggregation = model.reflect_on_aggregation(key)
|
242
|
+
value.instance_variable_get(:@backing_record).sync!
|
243
|
+
end
|
244
|
+
end
|
245
|
+
@changed_attributes = []
|
218
246
|
@saving = false
|
219
247
|
@errors = nil
|
248
|
+
# set the vector - this only happens when a new record is saved
|
249
|
+
@vector = [@model, ["find_by_#{@model.primary_key}", id]] if (!vector or vector.empty?) and id and id != ""
|
220
250
|
self
|
221
251
|
end
|
222
252
|
|
223
253
|
def sync_attribute(attribute, value)
|
224
254
|
@synced_attributes[attribute] = attributes[attribute] = value
|
225
255
|
@synced_attributes[attribute] = value.dup if value.is_a? ReactiveRecord::Collection
|
256
|
+
@changed_attributes.delete(attribute)
|
226
257
|
value
|
227
258
|
end
|
228
259
|
|
@@ -231,6 +262,7 @@ module ReactiveRecord
|
|
231
262
|
@ar_instance.send("#{attribute}=", @synced_attributes[attribute])
|
232
263
|
end
|
233
264
|
@attributes.delete_if { |attribute, value| !@synced_attributes.has_key?(attribute) }
|
265
|
+
@changed_attributes = []
|
234
266
|
@errors = nil
|
235
267
|
end
|
236
268
|
|
@@ -239,14 +271,16 @@ module ReactiveRecord
|
|
239
271
|
@saving = true
|
240
272
|
end
|
241
273
|
|
242
|
-
def
|
274
|
+
def errors!(errors)
|
275
|
+
@errors = errors and ActiveModel::Error.new(errors)
|
276
|
+
end
|
277
|
+
|
278
|
+
def saved! # sets saving to false AND notifies
|
243
279
|
@saving = false
|
244
|
-
|
245
|
-
if errors
|
246
|
-
#errors.each { |attribute, error| React::State.set_state(self, attribute, attributes[attribute]) }
|
247
|
-
React::State.set_state(self, self, :errors)
|
248
|
-
elsif !data_loading?
|
280
|
+
if !@errors or @errors.empty?
|
249
281
|
React::State.set_state(self, self, :saved)
|
282
|
+
elsif !data_loading?
|
283
|
+
React::State.set_state(self, self, :error)
|
250
284
|
end
|
251
285
|
self
|
252
286
|
end
|
@@ -304,7 +338,11 @@ module ReactiveRecord
|
|
304
338
|
elsif association = @model.reflect_on_association(method) and association.collection?
|
305
339
|
@attributes[method] = Collection.new(association.klass, @ar_instance, association)
|
306
340
|
elsif aggregation = @model.reflect_on_aggregation(method)
|
307
|
-
@attributes[method] = aggregation.klass.new
|
341
|
+
@attributes[method] = aggregation.klass.new.tap do |aggregate|
|
342
|
+
backing_record = aggregate.instance_variable_get(:@backing_record)
|
343
|
+
backing_record.aggregate_owner = self
|
344
|
+
backing_record.aggregate_attribute = method
|
345
|
+
end
|
308
346
|
end
|
309
347
|
end
|
310
348
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ReactiveRecord
|
2
2
|
|
3
3
|
class Collection
|
4
|
-
|
4
|
+
|
5
5
|
def initialize(target_klass, owner = nil, association = nil, *vector)
|
6
6
|
@owner = owner # can be nil if this is an outer most scope
|
7
7
|
@association = association
|
@@ -13,7 +13,7 @@ module ReactiveRecord
|
|
13
13
|
end
|
14
14
|
@scopes = {}
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def dup_for_sync
|
18
18
|
self.dup.instance_eval do
|
19
19
|
@collection = @collection.dup if @collection
|
@@ -52,11 +52,11 @@ module ReactiveRecord
|
|
52
52
|
scope = [scope, *args] if args.count > 0
|
53
53
|
@scopes[scope] ||= Collection.new(@target_klass, @owner, @association, *@vector, [scope])
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def proxy_association
|
57
57
|
@association || self # returning self allows this to work with things like Model.all
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def klass
|
61
61
|
@target_klass
|
62
62
|
end
|
@@ -64,17 +64,24 @@ module ReactiveRecord
|
|
64
64
|
|
65
65
|
def <<(item)
|
66
66
|
backing_record = item.instance_variable_get(:@backing_record)
|
67
|
-
if backing_record and @owner and @association and inverse_of = @association.inverse_of
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
67
|
+
# if backing_record and @owner and @association and inverse_of = @association.inverse_of
|
68
|
+
# item.attributes[inverse_of].attributes[@association.attribute].delete(item) if item.attributes[inverse_of] and item.attributes[inverse_of].attributes[@association.attribute]
|
69
|
+
# item.attributes[inverse_of] = @owner
|
70
|
+
# React::State.set_state(backing_record, inverse_of, @owner) unless backing_record.data_loading?
|
71
|
+
# end
|
72
|
+
#all << item unless all.include? item
|
72
73
|
all << item unless all.include? item
|
74
|
+
if backing_record and @owner and @association and inverse_of = @association.inverse_of and item.attributes[inverse_of] != @owner
|
75
|
+
current_association = item.attributes[inverse_of]
|
76
|
+
backing_record.update_attribute(inverse_of, @owner)
|
77
|
+
current_association.attributes[@association.attribute].delete(item) if current_association and current_association.attributes[@association.attribute]
|
78
|
+
@owner.instance_variable_get(:@backing_record).update_attribute(@association.attribute) # forces a check if association contents have changed from synced values
|
79
|
+
end
|
73
80
|
@collection.delete(@dummy_record)
|
74
81
|
@dummy_record = @dummy_collection = nil
|
75
82
|
self
|
76
83
|
end
|
77
|
-
|
84
|
+
|
78
85
|
[:first, :last].each do |method|
|
79
86
|
define_method method do |*args|
|
80
87
|
if args.count == 0
|
@@ -84,7 +91,7 @@ module ReactiveRecord
|
|
84
91
|
end
|
85
92
|
end
|
86
93
|
end
|
87
|
-
|
94
|
+
|
88
95
|
def replace(new_array)
|
89
96
|
#return new_array if @collection == new_array #not sure we need this anymore
|
90
97
|
@dummy_collection.notify if @dummy_collection
|
@@ -103,33 +110,36 @@ module ReactiveRecord
|
|
103
110
|
|
104
111
|
def delete(item)
|
105
112
|
if @owner and @association and inverse_of = @association.inverse_of
|
106
|
-
item.attributes[inverse_of]
|
107
|
-
|
108
|
-
|
113
|
+
if backing_record = item.instance_variable_get(:@backing_record) and backing_record.attributes[inverse_of] == @owner
|
114
|
+
# the if prevents double update if delete is being called from << (see << above)
|
115
|
+
backing_record.update_attribute(inverse_of, nil)
|
116
|
+
end
|
117
|
+
all.delete(item).tap { @owner.instance_variable_get(:@backing_record).update_attribute(@association.attribute) } # forces a check if association contents have changed from synced values
|
118
|
+
else
|
119
|
+
all.delete(item)
|
109
120
|
end
|
110
|
-
all.delete(item)
|
111
121
|
end
|
112
122
|
|
113
123
|
def method_missing(method, *args, &block)
|
114
124
|
if [].respond_to? method
|
115
125
|
all.send(method, *args, &block)
|
116
|
-
elsif @target_klass.respond_to? method
|
126
|
+
elsif @target_klass.respond_to?(method) or (args.count == 1 && method =~ /^find_by_/)
|
117
127
|
apply_scope(method, *args)
|
118
128
|
else
|
119
129
|
super
|
120
130
|
end
|
121
131
|
end
|
122
|
-
|
132
|
+
|
123
133
|
protected
|
124
|
-
|
134
|
+
|
125
135
|
def dummy_record
|
126
136
|
@dummy_record
|
127
137
|
end
|
128
|
-
|
138
|
+
|
129
139
|
def collection
|
130
140
|
@collection
|
131
141
|
end
|
132
|
-
|
142
|
+
|
133
143
|
def dummy_collection
|
134
144
|
@dummy_collection
|
135
145
|
end
|
@@ -35,7 +35,12 @@ module ReactiveRecord
|
|
35
35
|
|
36
36
|
isomorphic_method(:fetch_from_db) do |f, vector|
|
37
37
|
# vector must end with either "*all", or be a simple attribute
|
38
|
-
|
38
|
+
begin
|
39
|
+
f.send_to_server [vector.shift.name, *vector] if RUBY_ENGINE == 'opal'
|
40
|
+
rescue Exception => e
|
41
|
+
`debugger`
|
42
|
+
nil
|
43
|
+
end
|
39
44
|
f.when_on_server { @server_data_cache[*vector] }
|
40
45
|
end
|
41
46
|
|
@@ -188,7 +193,7 @@ module ReactiveRecord
|
|
188
193
|
|
189
194
|
if RUBY_ENGINE == 'opal'
|
190
195
|
|
191
|
-
def save(&block)
|
196
|
+
def save(validate, &block)
|
192
197
|
|
193
198
|
if data_loading?
|
194
199
|
|
@@ -208,13 +213,11 @@ module ReactiveRecord
|
|
208
213
|
backing_records = {self.object_id => self} # for quick lookup of records that have been or will be processed [record.object_id] => record
|
209
214
|
|
210
215
|
add_new_association = lambda do |record, attribute, assoc_record|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
backing_records[assoc_record.object_id] = assoc_record
|
215
|
-
end
|
216
|
-
associations << {parent_id: record.object_id, attribute: attribute, child_id: assoc_record.object_id}
|
216
|
+
unless backing_records[assoc_record.object_id]
|
217
|
+
records_to_process << assoc_record
|
218
|
+
backing_records[assoc_record.object_id] = assoc_record
|
217
219
|
end
|
220
|
+
associations << {parent_id: record.object_id, attribute: attribute, child_id: assoc_record.object_id}
|
218
221
|
end
|
219
222
|
|
220
223
|
record_index = 0
|
@@ -236,7 +239,7 @@ module ReactiveRecord
|
|
236
239
|
elsif record.changed?(attribute)
|
237
240
|
output_attributes[attribute] = value
|
238
241
|
end
|
239
|
-
end
|
242
|
+
end if record.changed?
|
240
243
|
record_index += 1
|
241
244
|
end
|
242
245
|
|
@@ -244,7 +247,7 @@ module ReactiveRecord
|
|
244
247
|
|
245
248
|
promise = Promise.new
|
246
249
|
|
247
|
-
HTTP.post(`window.ReactiveRecordEnginePath`+"/save", payload: {models: models, associations: associations}).then do |response|
|
250
|
+
HTTP.post(`window.ReactiveRecordEnginePath`+"/save", payload: {models: models, associations: associations, validate: validate}).then do |response|
|
248
251
|
begin
|
249
252
|
response.json[:models] = response.json[:saved_models].collect do |item|
|
250
253
|
backing_records[item[0]].ar_instance
|
@@ -253,17 +256,19 @@ module ReactiveRecord
|
|
253
256
|
if response.json[:success]
|
254
257
|
response.json[:saved_models].each { | item | backing_records[item[0]].sync!(item[2]) }
|
255
258
|
else
|
256
|
-
response.json[:saved_models].each { | item | backing_records[item[0]].saved! item[3] }
|
257
259
|
log("Reactive Record Save Failed: #{response.json[:message]}", :error)
|
258
260
|
response.json[:saved_models].each do | item |
|
259
261
|
log(" Model: #{item[1]}[#{item[0]}] Attributes: #{item[2]} Errors: #{item[3]}", :error) if item[3]
|
260
262
|
end
|
261
263
|
end
|
262
264
|
|
265
|
+
response.json[:saved_models].each { | item | backing_records[item[0]].errors! item[3] }
|
266
|
+
|
263
267
|
yield response.json[:success], response.json[:message], response.json[:models] if block
|
264
268
|
promise.resolve response.json
|
265
269
|
|
266
|
-
backing_records.each { |id, record| record.saved! }
|
270
|
+
backing_records.each { |id, record| record.saved! }
|
271
|
+
|
267
272
|
rescue Exception => e
|
268
273
|
puts "Save Failed: #{e}"
|
269
274
|
end
|
@@ -279,7 +284,7 @@ module ReactiveRecord
|
|
279
284
|
|
280
285
|
else
|
281
286
|
|
282
|
-
def self.save_records(models, associations, acting_user)
|
287
|
+
def self.save_records(models, associations, acting_user, validate)
|
283
288
|
|
284
289
|
reactive_records = {}
|
285
290
|
new_models = []
|
@@ -288,7 +293,7 @@ module ReactiveRecord
|
|
288
293
|
models.each do |model_to_save|
|
289
294
|
attributes = model_to_save[:attributes]
|
290
295
|
model = Object.const_get(model_to_save[:model])
|
291
|
-
id = attributes
|
296
|
+
id = attributes.delete(model.primary_key) # if we are saving existing model primary key value will be present
|
292
297
|
reactive_records[model_to_save[:id]] = if id
|
293
298
|
record = model.find(id)
|
294
299
|
keys = record.attributes.keys
|
@@ -315,27 +320,57 @@ module ReactiveRecord
|
|
315
320
|
end
|
316
321
|
end
|
317
322
|
|
323
|
+
puts "!!!!!!!!!!!!!!attributes updated"
|
324
|
+
|
318
325
|
ActiveRecord::Base.transaction do
|
319
326
|
|
320
327
|
associations.each do |association|
|
321
328
|
parent = reactive_records[association[:parent_id]]
|
322
329
|
parent.instance_variable_set("@reactive_record_#{association[:attribute]}_changed", true)
|
323
330
|
if parent.class.reflect_on_aggregation(association[:attribute].to_sym)
|
324
|
-
parent.send(
|
331
|
+
puts ">>>>>>AGGREGATE>>>> #{parent.class.name}.send('#{association[:attribute]}=', #{reactive_records[association[:child_id]]})"
|
332
|
+
aggregate = reactive_records[association[:child_id]]
|
333
|
+
current_attributes = parent.send(association[:attribute]).attributes
|
334
|
+
puts "current parent attributes = #{current_attributes}"
|
335
|
+
new_attributes = aggregate.attributes
|
336
|
+
puts "current child attributes = #{new_attributes}"
|
337
|
+
merged_attributes = current_attributes.merge(new_attributes) { |k, n, o| n or o }
|
338
|
+
puts "merged attributes = #{merged_attributes}"
|
339
|
+
aggregate.assign_attributes(merged_attributes)
|
340
|
+
puts "aggregate attributes after merge = #{aggregate.attributes}"
|
341
|
+
parent.send("#{association[:attribute]}=", aggregate)
|
342
|
+
puts "updated is frozen? #{aggregate.frozen?}, parent attributes = #{parent.send(association[:attribute]).attributes}"
|
325
343
|
elsif parent.class.reflect_on_association(association[:attribute].to_sym).collection?
|
326
|
-
parent.send(
|
344
|
+
puts ">>>>>>>>>> #{parent.class.name}.send('#{association[:attribute]}') << #{reactive_records[association[:child_id]]})"
|
345
|
+
#parent.send("#{association[:attribute]}") << reactive_records[association[:child_id]]
|
346
|
+
puts "Skipped (should be done by belongs to)"
|
327
347
|
else
|
348
|
+
puts ">>>>ASSOCIATION>>>> #{parent.class.name}.send('#{association[:attribute]}=', #{reactive_records[association[:child_id]]})"
|
328
349
|
parent.send("#{association[:attribute]}=", reactive_records[association[:child_id]])
|
350
|
+
puts "updated"
|
329
351
|
end
|
330
352
|
end if associations
|
331
353
|
|
354
|
+
puts "!!!!!!!!!!!!associations updated"
|
355
|
+
|
332
356
|
has_errors = false
|
333
357
|
|
334
358
|
saved_models = reactive_records.collect do |reactive_record_id, model|
|
335
|
-
|
336
|
-
|
359
|
+
puts "saving rr_id: #{reactive_record_id} model.object_id: #{model.object_id} frozen? <#{model.frozen?}>"
|
360
|
+
if model.frozen?
|
361
|
+
puts "validating frozen model #{model.class.name} #{model} (reactive_record_id = #{reactive_record_id})"
|
362
|
+
valid = model.valid?
|
363
|
+
puts "has_errors before = #{has_errors}, validate= #{validate}, !valid= #{!valid} (validate and !valid) #{validate and !valid}"
|
364
|
+
has_errors ||= (validate and !valid)
|
365
|
+
puts "validation complete errors = <#{!valid}>, #{model.errors.messages} has_errors #{has_errors}"
|
366
|
+
[reactive_record_id, model.class.name, model.attributes, (valid ? nil : model.errors.messages)]
|
367
|
+
elsif !model.id or model.changed?
|
368
|
+
puts "saving #{model.class.name} #{model} (reactive_record_id = #{reactive_record_id})"
|
369
|
+
saved = model.check_permission_with_acting_user(acting_user, new_models.include?(model) ? :create_permitted? : :update_permitted?).save(validate: validate)
|
337
370
|
has_errors ||= !saved
|
338
|
-
|
371
|
+
messages = model.errors.messages if (validate and !saved) or (!validate and !model.valid?)
|
372
|
+
puts "saved complete errors = <#{!saved}>, #{messages} has_errors #{has_errors}"
|
373
|
+
[reactive_record_id, model.class.name, model.attributes, messages]
|
339
374
|
end
|
340
375
|
end.compact
|
341
376
|
|
@@ -346,6 +381,7 @@ module ReactiveRecord
|
|
346
381
|
{success: true, saved_models: saved_models }
|
347
382
|
|
348
383
|
rescue Exception => e
|
384
|
+
puts "exception #{e}"
|
349
385
|
|
350
386
|
{success: false, saved_models: saved_models, message: e.message}
|
351
387
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reactive-record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mitch VanDuyn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|