-
Notifications
You must be signed in to change notification settings - Fork 1
What Jacob Did
Jacob is the one who contributed the very first ActionCable involved feature to this project, which is the game-waiting-room feature. The control flow with AC involved is more complicated than what typically happens in Rails applications.
The control flow is initiated by clicking the button New Game, sending a http request. Next I will explain each component the control is passed through along the way, until it hits the very first page in the gaming cycle.
By default, no index method means render index.html.erb
. authenticate_user!
is a method provided by devise
In this file, there is just one piece of javascript code. Its duty is to call the subscription function to let the user to subscribe to GameWaitingRoomChannel. The subscription function is in a javascript/coffeescript file inside asset pipeline folders. This cause the js file to be loaded on every page. So if we directly subscribe there, we are letting authenticated users subscribe to GameWaitingRoomChannel on every page in the app. The action of subscribing is calling App.cable.subscriptions.create
which create a subscription instance. Encapsulating this function call in another function and call that function on a specific page makes the channel private to the page.
When a user subscribes, it triggers GameWaitingRoomChannel#subscribed
def subscribed
stream_for current_user
stream_from 'waiting-room'
add_current_user
end
private
def add_current_user
GameWaitingRoom.add(current_user)
@game = create_game if GameWaitingRoom.full?
CurrentUserBroadcastJob.perform_later(current_user, @game)
ParticipantsBroadcastJob.perform_now(@game)
end
We add current_user to GameWaitingRoom
. Note in Jacob's design we only have one waiting room at any moment. If the room has 3 players by far we create a new instance in database and assign it to the instance variable @game
. Then we handle updating info on the individual player's page to ActiveJob
.
include Templatable
def perform(user, game)
GameWaitingRoomChannel.broadcast_to user, data_for(game)
end
private
def data_for(game)
game ? game_starting(game) : game_waiting
end
data_for(game)
is a hash from which client-side js code for ActionCable can retrieve info broadcasted through the channel. Here game_starting
and game_waiting
are methods from module Templatable
. participants_broadcast_job.rb
does pretty much the same. I'll leave that to you.
It provides methods that return a hash containing two key-val pairs. One is a html snippet and the other is the html tag into which the snippet is about to be inserted. Depending on the path you will notice that views/game_waiting_room/_waiting.html.erb
and view/game_waiting_room/_starting.html.erb
will be rendered and put in the hash.
Now the data is ready to be broadcasted through the channel. Let's see how the client-side js code will handle the data coming through.
window.startGameWaitingRoomCable = ->
App.game = App.cable.subscriptions.create "GameWaitingRoomChannel",
received: (data) ->
@renderTemplate(data)
renderTemplate: (data) ->
target = $(data['target'])
# $().html() replace the content of the tag
# with the content in html()
target.html(data['template'])
It simply replaces the text inside the target html tag with the data we rendered in Templatable
The control flow ends here. Or does it?
In GameWaitingRoomChannel
we see some class method calls on GameWaitingRoom
. It's a non-persistent model with a redis queue to serve as the room. It defines a lot of instance methods and delegate the class method calls with the same name to a instance inside the class. It's a very convoluted approach. Rails provided helper delegate
is implemented in a way that by default you can only delegate instance methods to instance methods. Check out the source code delegation.rb. In order to delegate class methods to class methods, Jacob opened singleton class inside the class definition.
Once the room is full, this html snippet will replace the waiting room page. It also contains a piece of js code which sends a http request causing you to be redirected to the first page of the gaming cycle. So the journey begins.