reactive-record 0.7.15 → 0.7.16

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: 7855dd3a22d52663865ebec642e73a24b63edd47
4
- data.tar.gz: 3a383477635ae0dc2cab7375e761acbb9a568323
3
+ metadata.gz: 139439c144b766200fccb72d67240cbfec0d6eae
4
+ data.tar.gz: 1d67f45f99d68e4e2dd0ac5db2ee88885b491e80
5
5
  SHA512:
6
- metadata.gz: 7628e05b00f071724498ba1e9cc562e1786f26818385a021003250428f0b767d49d7afd9a9722beef43c70678856ce7eb9256fc0ce90b7888a111d2ea8d64bae
7
- data.tar.gz: 7fed6602d7e6556c50ccd9cd18ce25fa09c1803fcfe55ebe979147b690f0d5460bb0a151f82e103da4ea779773acf6d7d9ee187b369d0dea5d28253fb6da45ce
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 { hash.each { |attribute, value| reactive_set!(attribute, value) unless attribute == primary_key } }
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, aggregate_method, *vector)
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
- was_changed = changed2(@attributes.dup)
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 changed?(*args)
187
- changed2(if args.count == 0
188
- React::State.get_state(self, self)
189
- @attributes.dup
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
- React::State.get_state(@attributes, args[0])
192
- {args[0] => @attributes[args[0]]}
193
- end)
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 changed2(attrs)
197
- attrs.each do |attribute, value|
198
- if association = @model.reflect_on_association(attribute) and association.collection? and value
199
- return true unless value == @synced_attributes[attribute]
200
- elsif !@synced_attributes.has_key?(attribute)
201
- return true
202
- elsif @synced_attributes[attribute] != value
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 { |key, value| @synced_attributes[key] = value.dup_for_sync if value.is_a? Collection }
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 saved!(errors = nil) # sets saving to false AND notifies
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
- @errors = ActiveModel::Error.new(errors)
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
- 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
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] = nil
107
- backing_record = item.instance_variable_get(:@backing_record)
108
- React::State.set_state(backing_record, inverse_of, nil) unless backing_record.data_loading?
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
- f.send_to_server [vector.shift.name, *vector] if RUBY_ENGINE == 'opal'
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
- if assoc_record.changed?
212
- unless backing_records[assoc_record.object_id]
213
- records_to_process << assoc_record
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! } if response.json[:success]
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[model.primary_key] # if we are saving existing model primary key value will be present
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("#{association[:attribute]}=", reactive_records[association[:child_id]])
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("#{association[:attribute]}") << reactive_records[association[:child_id]]
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
- unless model.frozen?
336
- saved = model.check_permission_with_acting_user(acting_user, new_models.include?(model) ? :create_permitted? : :update_permitted?).save
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
- [reactive_record_id, model.class.name, model.attributes, (saved ? nil : model.errors.messages)]
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
 
@@ -1,3 +1,3 @@
1
1
  module ReactiveRecord
2
- VERSION = "0.7.15"
2
+ VERSION = "0.7.16"
3
3
  end
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.15
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-18 00:00:00.000000000 Z
11
+ date: 2015-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails