Skip to content

Commit 151f7c2

Browse files
committed
has_many_through and poly specs all passing
1 parent 832fada commit 151f7c2

File tree

7 files changed

+64
-44
lines changed

7 files changed

+64
-44
lines changed

ruby/hyper-model/lib/reactive_record/active_record/associations.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def remove_member(member, owner)
193193

194194
def add_member(member, owner)
195195
owner.attributes[attribute] ||= ReactiveRecord::Collection.new(owner_class, owner, self)
196-
owner.attributes[attribute] << member
196+
owner.attributes[attribute]._internal_push member
197197
end
198198
end
199199
end

ruby/hyper-model/lib/reactive_record/active_record/reactive_record/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def sync_unscoped_collection!
253253
return if @create_sync
254254
@create_sync = true
255255
end
256-
model.unscoped << ar_instance
256+
model.unscoped._internal_push ar_instance
257257
@synced_with_unscoped = !@synced_with_unscoped
258258
end
259259

ruby/hyper-model/lib/reactive_record/active_record/reactive_record/collection.rb

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def [](index)
7777
(@collection.length..index).each do |i|
7878
new_dummy_record = ReactiveRecord::Base.new_from_vector(@target_klass, nil, *@vector, "*#{i}")
7979
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?
8082
@collection << new_dummy_record
8183
end
8284
end
@@ -212,7 +214,7 @@ def related_records_for(record)
212214
return [] unless attrs[@association.inverse_of] == @owner
213215
if !@association.through_association
214216
[record]
215-
elsif (source = attrs[@association.source])
217+
elsif (source = attrs[@association.source]) && source.is_a?(@target_klass)
216218
[source]
217219
else
218220
[]
@@ -233,7 +235,8 @@ def live_scopes
233235
end
234236

235237
def in_this_collection(related_records)
236-
return related_records unless @association
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?
237240
related_records.select do |r|
238241
r.backing_record.attributes[@association.inverse_of] == @owner
239242
end
@@ -406,7 +409,11 @@ def push_and_update_belongs_to(id)
406409
def set_belongs_to(child)
407410
if @owner
408411
# TODO this is major broken...current
409-
child.send("#{@association.inverse_of}=", @owner) if @association && !@association.through_association
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
410417
elsif @parent
411418
@parent.set_belongs_to(child)
412419
end
@@ -421,7 +428,10 @@ def set_belongs_to(child)
421428

422429
def update_child(item)
423430
backing_record = item.backing_record
424-
if backing_record && @owner && @association && item.attributes[@association.inverse_of] != @owner #&& [email protected]_association?
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?
425435
inverse_of = @association.inverse_of
426436
current_association_value = item.attributes[inverse_of]
427437
backing_record.virgin = false unless backing_record.data_loading?
@@ -440,6 +450,17 @@ def update_child(item)
440450
end
441451

442452
def push(item)
453+
if (through_association = @association&.through_association)
454+
through_association.klass.create(@association.inverse_of => @owner, @association.source => item)
455+
self
456+
else
457+
_internal_push(item)
458+
end
459+
end
460+
461+
alias << push
462+
463+
def _internal_push(item)
443464
item.itself # force get of at least the id
444465
if collection
445466
self.force_push item
@@ -455,8 +476,6 @@ def push(item)
455476
self
456477
end
457478

458-
alias << push
459-
460479
def sort!(*args, &block)
461480
replace(sort(*args, &block))
462481
end
@@ -529,20 +548,20 @@ def internal_replace(new_array)
529548
if new_array.is_a? Collection
530549
@dummy_collection = new_array.dummy_collection
531550
@dummy_record = new_array.dummy_record
532-
new_array.collection.each { |item| self << item } if new_array.collection
551+
new_array.collection.each { |item| _internal_push item } if new_array.collection
533552
else
534553
@dummy_collection = @dummy_record = nil
535-
new_array.each { |item| self << item }
554+
new_array.each { |item| _internal_push item }
536555
end
537556
notify_of_change new_array
538557
end
539558

540559
def delete(item)
541560
unsaved_children.delete(item)
542561
notify_of_change(
543-
if @owner && @association && !@association.through_association?
562+
if @owner && @association
544563
inverse_of = @association.inverse_of
545-
if (backing_record = item.backing_record) && item.attributes[inverse_of] == @owner
564+
if (backing_record = item.backing_record) && item.attributes[inverse_of] == @owner && !@association.through_association?
546565
# the if prevents double update if delete is being called from << (see << above)
547566
backing_record.update_belongs_to(inverse_of, nil)
548567
end

ruby/hyper-model/lib/reactive_record/active_record/reactive_record/getters.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ def find_association(association, id, klass)
123123
inverse_of = association.inverse_of(instance)
124124
instance_backing_record_attributes = instance.attributes
125125
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
126131
if inverse_association.collection?
127132
instance_backing_record_attributes[inverse_of] = if id and id != ""
128133
Collection.new(@model, instance, inverse_association, association.klass, ["find", id], inverse_of)

ruby/hyper-model/lib/reactive_record/active_record/reactive_record/setters.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def set_non_ar_aggregate(aggregation, raw_value)
2929
end
3030

3131
def set_has_many(assoc, raw_value)
32-
puts "********* set_has_many called **********"
3332
set_common(assoc.attribute, raw_value) do |value, attr|
3433
# create a new collection to hold value, shove it in, and return the new collection
3534
# the replace method will take care of updating the inverse belongs_to links as
@@ -54,12 +53,9 @@ def set_belongs_to(assoc, raw_value)
5453
end
5554

5655
def set_belongs_to_via_has_many(orig, value)
57-
puts "set_belongs_to_via_has_many(#{orig.inspect}, #{value.inspect})"
5856
assoc = orig.inverse
5957
attr = assoc.attribute
6058
current_value = @attributes[attr]
61-
puts "set_belongs_to_via_has_many(#{orig.attribute}, #{attr}, #{current_value.inspect}, #{value.inspect})"
62-
6359
update_has_many_through_associations assoc, orig, current_value, :remove_member
6460
update_has_many_through_associations assoc, orig, value, :add_member
6561
remove_current_inverse_attribute assoc, orig, current_value
@@ -179,7 +175,7 @@ def add_new_inverse_attribute(association, orig, model)
179175

180176
def push_onto_collection(model, association, ar_instance)
181177
@attributes[association.attribute] ||= Collection.new(model, @ar_instance, association)
182-
@attributes[association.attribute] << ar_instance
178+
@attributes[association.attribute]._internal_push ar_instance
183179
end
184180

185181
# class Membership < ActiveRecord::Base

ruby/hyper-model/lib/reactive_record/server_data_cache.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,7 @@ def self.load_from_json(tree, target = nil)
492492
# not sure if its necessary to check the id above... is it possible to for the method to be an association but not have an id?
493493
klass = value[:model_name] ? Object.const_get(value[:model_name].first) : association.klass
494494
new_target = ReactiveRecord::Base.find_by_id(klass, value[:id].first)
495-
puts "got a new_target #{new_target.inspect}"
496495
target.send "#{method}=", new_target
497-
puts "and that worked!"
498496
elsif !(target.class < ActiveRecord::Base)
499497
new_target = target.send(*method)
500498
# value is an array if scope returns nil, so we destroy the bogus record

ruby/hyper-model/spec/batch7/poly_assoc_spec.rb

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ def self.build_tables
9292
has_one :picture, as: :imageable
9393
end
9494

95+
class ReactiveRecord::Collection
96+
end if RUBY_ENGINE == 'opal'
9597

9698
class Membership < ActiveRecord::Base
9799
def self.build_tables
@@ -150,8 +152,6 @@ def self.build_tables
150152
has_many :groups, through: :memberships, source: :memerable, source_type: 'Group'
151153
has_many :projects, through: :memberships, source: :memerable, source_type: 'Project'
152154
end
153-
154-
155155
end
156156

157157
[Picture, Employee, Product, Membership, Project, Group, Uzer].each { |klass| klass.build_tables }
@@ -180,10 +180,8 @@ def compare_to_server(model, expression, expected_result, load=true)
180180
@picture21 = Picture.create(name: 'picture21', imageable: @imageable2)
181181
@picture22 = Picture.create(name: 'picture22', imageable: @imageable2)
182182
@imageable3 = Product.create(name: 'imageable3', description: 'product2 description')
183-
184183
end
185184

186-
187185
it 'read belongs_to' do
188186
compare_to_server @picture11, 'imageable.name', 'imageable1'
189187
compare_to_server @picture11, 'imageable.ss', '123'
@@ -278,48 +276,52 @@ def compare_to_server(model, expression, expected_result, load=true)
278276
@project1 = Project.create(name: 'project1', project_data: 'project data1')
279277
@project2 = Project.create(name: 'project2', project_data: 'project data2')
280278
@project3 = Project.create(name: 'project3', project_data: 'project data3')
279+
# client scopes have the be 'live' on the display to be automatically updated
280+
# so we have this handy component to keep the @group1.uzers scope live.
281+
mount 'Testing123' do
282+
class Testing123 < HyperComponent
283+
render(UL) do
284+
Group.find(1).uzers.each { |uzer| LI { uzer.id.to_s }}
285+
end
286+
end
287+
end
281288
end
282289

283290
it 'loads previously defined data client side' do
284291
@uzer1.groups << @group1
285-
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id]
292+
wait_for_ajax
293+
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id], false
286294
end
287295

288296
it 'creates due to a broadcast client side' do
289-
compare_to_server @group1, 'uzers.collect(&:id)', [] # client side
290-
@uzer1.groups << @group1 # server side
291-
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id], false # client side
297+
@uzer1.groups << @group1
298+
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id], false
292299
end
293300

294301
it 'destroys due to a broadcast client side' do
295302
@uzer1.groups << @group1 # server side
296-
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id] # client
303+
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id], false # client
297304
Membership.find_by(uzer: @uzer1, memerable: @group1).destroy # server side
298-
compare_to_server @group1, 'uzers.count', 0 # client side
305+
compare_to_server @group1, 'uzers.count', 0, false # client side
299306
end
300307

301308
it 'updates the server when new entries are made on the client' do
302-
# Not Working!
303-
evaluate_promise do
304-
uzer = Uzer.find(1)
305-
group = Group.find(1)
306-
project = Membership.new(uzer: uzer, memerable: group)
307-
#uzer.groups << group # client side
308-
#group.save # needed for client side semantics
309-
project.save
309+
evaluate_ruby do
310+
Uzer.find(1).groups << Group.find(1) # client side
310311
end
311-
#binding.pry
312+
wait_for_ajax
312313
@group1.reload
313-
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id] # server side
314+
compare_to_server @group1, 'uzers.collect(&:id)', [@uzer1.id], false # server side
314315
end
315316

316317
it 'updates the server when entries are deleted on the client' do
317-
# Not converted to client side execution
318318
@uzer1.groups << @group1 # server side
319-
Membership.find_by(uzer: @uzer1, memerable: @group1).destroy # client side
320-
expect(@group1.uzers.count).to eq(0) # server side
319+
evaluate_promise do
320+
Hyperstack::Model.load do
321+
Membership.find_by(uzer_id: 1, memerable_id: 1, memerable_type: 'Group')
322+
end.then(&:destroy)
323+
end
324+
compare_to_server @group1, 'uzers.count', 0, false
321325
end
322-
323326
end
324-
325327
end

0 commit comments

Comments
 (0)