ActionCable
Real-time web applications for fun and profit
@sophiedeziel
Requirements
Basic concepts
Config
Creating a game
Profit
In this talk, we will you will learn amazing things:
Read the code at your ease:
http://slides.com/sophiedeziel/actioncables/
# You can read the code in the
# slides at your ease.
#
#
# This will remain accessible
# after the talk so you can
# come back to it.
Talk.new('ActionCables').start(Time.now)
Requirements
Basic concepts
Config
Creating a game
Profit
What is a WebSocket?
- Standard (RFC 6455)
- Full-Duplex
- Used aside of HTTP
- Supports encrypted and unencrypted connections
Wow! is it well supported?
Yes.
There are existing solutions for rails
- websocket_rails gem
- faye_rails gem
- Pusher
- Pubsubhubbub
- Firebase
- Still in alpha version
- Announced for Rails 5
- But we can try it!
ActionCables is coming soon...
Important concepts
Your Rails server
# Some code
# ...
render text: 'Hello World!'
User
Your web application
Your Action Cable server
Important concepts
- Action Cable server
- Connection Instance
- WebSocket connection
- Consumer
- Channel
- Subscription
- Streaming
- Broadcasting
Requirements
Basic concepts
Config
Creating a game
Profit
- Ruby >= 2.2.0
- Works on Rails 4.2
- Redis
- multi-threaded web server (ex: Puma)
Recipe:
Gemfile
source 'https://rubygems.org'
# Default rails gems
gem 'rails', '4.2.2'
gem 'sqlite3'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
# For Action Cables
gem 'actioncable', git: 'https://github.com/rails/actioncable'
gem 'puma'
group :development, :test do
gem 'byebug'
gem 'web-console', '~> 2.0'
gem 'spring'
end
Requirements
Basic concepts
Config
Creating a game
Profit
config/redis/cable.yml
default: &default
:url: redis://localhost:6379
:host: localhost
:port: 6379
:timeout: 1
:inline: true
development: *default
test: *default
production: *default
cable/config.ru
require ::File.expand_path('../../config/environment', __FILE__)
Rails.application.eager_load!
require 'action_cable/process/logging'
run ActionCable.server
Start the WebSocket server
> bundle exec puma -p 28080 cable/config.ru
Or
bin/cable
# /bin/bash
bundle exec puma -p 28080 cable/config.ru
> . bin/cable
app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
app/channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
Hosting on heroku
Two solutions:
- Rack Middleware
http://www.thegreatcodeadventure.com/deploying-action-cable-to-heroku/
- Two separate apps
(a bit complicated and unnecessary)
Hosting on a virtual machine using NGinx
upstream app {
server unix:/home/sophie/actioncable-game/shared/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name localhost;
root /home/sophie/actioncable-game/public;
try_files $uri/index.html $uri @app;
location @app {
proxy_pass http://app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server localhost:28080;
}
server {
listen 8020;
location / {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
Requirements
Basic concepts
Config
Creating a game
Profit
Creating a channel
class ApplicationChannel < ApplicationCable::Channel
end
class GameChannel < ApplicationChannel
def subscribed
end
def unsubscribed
end
def my_action
end
def my_other_action
end
end
Sending data from the client side (easy stuff..)
# app/assets/javascript/application_cable.coffee
@App = {}
App.cable = Cable.createConsumer 'ws://game.sophiedeziel.com:8020'
# app/assets/javascripts/cable/subscriptions/game.coffee
App.game = App.cable.subscriptions.create "GameChannel",
connected: ->
# some code when connected
my_method: (data) ->
@perform 'my_action', data
# Anywhere in your application
App.game.my_method({ player_name: 'Chuck Norris', score: 'over 9000' })
Broadcasting from the server (wow! This is also easy)
class GameChannel < ApplicationChannel
periodically :poke_users, every: 1.second
def subscribed
stream_from "game_channel"
end
private
def poke_users
ActionCable.server.broadcast "game_channel", { message: 'Poke!', from: 'Server' }
end
end
# From anywhere in your app:
ActionCable.server.broadcast "game_channel", { message: 'Poke!', from: 'Chuck Norris' }
#app/assets/javascripts/cable/subscriptions/game.coffee
App.game = App.cable.subscriptions.create "GameChannel",
received: (data) ->
if data['message'] == 'Poke!' && data['Chuck Norris']
players.kill()
else
players.send_message(data)
http://game.sophiedeziel.com
Requirements
Basic concepts
Config
Creating a game
Profit
- Build an awesome app
- Monetize it or open-source it.
Conclusion
- Still tiny compared to the other solutions
- There are some rough edges
- Fun and easy to play with
- I spent 10x time debugging my javascript game than experimenting with Action Cable
Please, ask some questions
Sources & Links
- https://github.com/rails/actioncable
- https://en.wikipedia.org/wiki/WebSocket
-
The Definitive Guide to HTML5 WebSocket
by Vanessa Wang, Frank Salim and Peter Moskovits - http://www.thegreatcodeadventure.com/deploying-action-cable-to-heroku/
The game's sources:
ActionCable, Real-time applications for fun and profit
By Sophie Déziel
ActionCable, Real-time applications for fun and profit
I gave that talk on September 15th 2015 at Montreal.rb meetup.
- 1,619