Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Realtime web apps with RethinkDB and full-stack Ruby

Ryan Paul
September 30, 2015

Realtime web apps with RethinkDB and full-stack Ruby

Learn how to build a full-stack realtime web application with Ruby on the frontend and the backend. Get a hands-on look at how to use Opal, the Ruby-to-JavaScript transpiler, to build a Ruby-based web frontend that communicates with a Ruby backend via WebSockets.

Ryan Paul

September 30, 2015

More Decks by Ryan Paul

Other Decks in Programming


  1. FULL STACK RUBY Realtime web apps with RethinkDB & Opal

  2. Ryan Paul RethinkDB Evangelist @segphault

  3. The Stack RethinkDB Thin Sinatra Faye WS Opal WS Client

  4. Track live updates with RethinkDB changefeeds

  5. What is RethinkDB? • Open source database for building realtime

    web applications • NoSQL database that stores schemaless JSON documents • Distributed database that is easy to scale
  6. Built for Realtime Apps • Subscribe to change notifications from

    database queries • No more polling — the database pushes changes to your app • Reduce the amount of plumbing needed to stream live updates
  7. Subscribe to change notifications on database queries Changefeeds

  8. r.table("users").changes() Changefeeds Track changes on the users table

  9. Changefeeds • The changes command returns a cursor that receives

    updates • Each update includes the new and old value of the modified record
  10. r.table("users") .filter({name: "Bob"}).delete() Changefeed output: { new_val: null, old_val: {

    id: '362ae837-2e29-4695-adef-4fa415138f90', name: 'Bob', ... } } Changefeeds
  11. r.table("players") .orderBy({index: r.desc("score")}) .limit(3).changes() Track top three players by score

    Chain the changes command to an actual ReQL query: Changefeeds
  12. Building the backend with RethinkDB and Sinatra

  13. Backend • Running on Thin for EventMachine support • Sinatra

    for API endpoints and serving resources • Faye WebSockets for realtime messaging
  14. Changefeed EM.next_tick do conn = r.connect() r.table("todo").changes.em_run(conn) do |err, change|

    @clients.each {|c| c.send change.to_json } end end Send updates to all connected users
  15. WebSockets def setup_websocket ws ws.on(:close) { @clients.delete ws } ws.on(:open)

    { @clients << ws } ws.on :message do |msg| data = JSON.parse msg.data case data["command"] when "add" query r.table("todo") .insert text: data["text"], status: false when "update" query r.table("todo") .get(data["id"]) .update status: data["status"] end end end
  16. WebSockets Serve WebSockets on port 80 get "/" do if

    Faye::WebSocket.websocket? request.env ws = Faye::WebSocket.new request.env setup_websocket ws ws.rack_response else haml :index end end
  17. Ruby to JavaScript with the Opal transpiler project

  18. What is Opal? • Transpiler that converts Ruby to JavaScript

    • Based largely on Ruby 1.9 language spec • Includes runtime code that mimics Ruby environment • Supports some interop between Ruby and JavaScript
  19. Why Opal? • Use one language consistently throughout your project

    • Reuse (some) existing code • Ruby is powerful and expressive, well-suited for many tasks
  20. But Why? BECAUSE I CAN

  21. Why Not Opal? • Extra layer of abstraction introduces more

    complexity • Custom runtime code introduces some performance overhead • Under-documented moving target not conducive to maintainability
  22. Why Not Opal? seriously crazy tracebacks

  23. Asset setup in config.ru Dynamically serve transpiled assets $opal =

    Opal::Server.new do |s| s.append_path "client" s.main = "main" end map "/assets" do run $opal.sprockets end $opalinit = Opal::Processor.load_asset_code( $opal.sprockets, "main")
  24. Assets Drop $opalinit in a <script> tag !!! %html %head

    %title Test %script(src="/assets/main.js") %script= $opalinit %body
  25. Building the frontend with React.rb components

  26. React.rb • Opal-based wrapper for React • Lets you build

    component-based web frontend entirely in Ruby • Provides an intuitive DSL for generating HTML • Can be used on frontend or backend
  27. React.rb class App include React::Component def render h1 { "Hello,

    world!" } end end Defining a React.rb component
  28. React.rb class TodoAdd include React::Component def render div do input(type:

    "text", ref: "text") button {"Add"}.on(:click) do text = self.refs[:text].dom_node.value self.emit :add, text: text end end end end
  29. React.rb def transmit data @ws.puts data.to_json end def render div

    do present(TodoAdd).on :add do |data| transmit command: "add", text: data["text"] end end end
  30. The Stack RethinkDB Thin Sinatra Faye WS Opal WS Client

  31. Additional Resources • RethinkDB website:
 http://rethinkdb.com • Opal website:

    • React.rb project:
 https://github.com/zetachang/ react.rb