Skip to content

Commit f6f046e

Browse files
committed
closes #159
1 parent 2840307 commit f6f046e

File tree

2 files changed

+91
-3
lines changed

2 files changed

+91
-3
lines changed

ruby/hyper-operation/lib/hyper-operation/transport/client_drivers.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,35 @@ def self.production?
3535

3636

3737
if RUBY_ENGINE == 'opal'
38+
# Patch in a dummy copy of Model.load in case we are not using models
39+
# this will be defined properly by hyper-model
40+
module Model
41+
def self.load
42+
Promise.new.tap { |promise| promise.resolve(yield) }
43+
end unless respond_to?(:load)
44+
end
45+
3846
def self.connect(*channels)
3947
channels.each do |channel|
4048
if channel.is_a? Class
4149
IncomingBroadcast.connect_to(channel.name)
4250
elsif channel.is_a?(String) || channel.is_a?(Array)
4351
IncomingBroadcast.connect_to(*channel)
44-
elsif channel.id
45-
IncomingBroadcast.connect_to(channel.class.name, channel.id)
52+
elsif channel.respond_to?(:id)
53+
Hyperstack::Model.load do
54+
channel.id
55+
end.then do |id|
56+
raise "Hyperstack.connect cannot connect to #{channel.inspect}. "\
57+
"The id is nil. This can be caused by connecting to a model "\
58+
"that is not saved, or that does not exist." unless id
59+
IncomingBroadcast.connect_to(channel.class.name, id)
60+
end
4661
else
47-
raise "cannot connect to model before it has been saved"
62+
raise "Hyperstack.connect cannot connect to #{channel.inspect}.\n"\
63+
"Channels must be either a class, or a class name,\n"\
64+
"a string in the form 'ClassName-id',\n"\
65+
"an array in the form [class, id] or [class-name, id],\n"\
66+
"or an object that responds to the id method with a non-nil value"
4867
end
4968
end
5069
end

ruby/hyper-operation/spec/aaa_run_first/transports_spec.rb

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,5 +346,74 @@ def connect(*args)
346346
it 'has a anti_csrf_token' do
347347
expect_evaluate_ruby('Hyperstack.anti_csrf_token').to be_present
348348
end
349+
350+
it 'wait for an instance channel to be loaded before connecting' do
351+
# Make a pretend mini model, and allow it to be accessed by user-123
352+
stub_const "UserModelPolicy", Class.new
353+
stub_const "UserModel", Class.new
354+
UserModel.class_eval do
355+
def initialize(id)
356+
@id = id
357+
end
358+
def ==(other)
359+
id == other.id
360+
end
361+
def self.find(id)
362+
new(id)
363+
end
364+
def id
365+
@id.to_s
366+
end
367+
end
368+
UserModelPolicy.class_eval do
369+
regulate_instance_connections { UserModel.new(123) }
370+
end
371+
372+
# During checkin we will run this op. The spec will make sure it runs
373+
isomorphic do
374+
class CheckIn < Hyperstack::ControllerOp
375+
param :id
376+
validate { params.id == '123' }
377+
step { params.id }
378+
end
379+
end
380+
381+
382+
on_client do
383+
# Stub the user model on the client
384+
class UserModel
385+
def initialize(id)
386+
@id = id
387+
end
388+
def id
389+
@id.to_s
390+
end
391+
end
392+
# stub the normal Hyperstack::Model.load to call checkin
393+
# note that load returns a promise and so does checkin! Lovely
394+
module Hyperstack
395+
module Model
396+
def self.load
397+
CheckIn.run(id: yield)
398+
end
399+
end
400+
end
401+
end
402+
403+
# use action cable
404+
Hyperstack.configuration do |config|
405+
config.connect_session = false
406+
config.transport = :action_cable
407+
config.channel_prefix = "synchromesh"
408+
end
409+
410+
expect(CheckIn).to receive(:run).and_call_original
411+
evaluate_ruby "Hyperstack.connect(UserModel.new(123))"
412+
# the suite previously redefined connect so we have to call this to initiate
413+
# the connection
414+
evaluate_ruby "Hyperstack.go_ahead_and_connect"
415+
wait(10.seconds).for { Hyperstack::Connection.active }.to eq(['UserModel-123'])
416+
end
417+
349418
end
350419
end

0 commit comments

Comments
 (0)