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 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