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
Tweet

More Decks by Ryan Paul

Other Decks in Programming

Transcript

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

    View Slide

  2. Ryan Paul
    RethinkDB
    Evangelist
    @segphault

    View Slide

  3. The Stack
    RethinkDB Thin
    Sinatra
    Faye WS
    Opal
    WS Client
    React.rb
    Ruby Client
    STORAGE BACKEND FRONTEND

    View Slide

  4. Track live updates with
    RethinkDB changefeeds

    View Slide

  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

    View Slide

  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

    View Slide

  7. Subscribe to change notifications
    on database queries
    Changefeeds

    View Slide

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

    View Slide

  9. Changefeeds
    • The changes command returns a
    cursor that receives updates
    • Each update includes the new and
    old value of the modified record

    View Slide

  10. r.table("users")
    .filter({name: "Bob"}).delete()
    Changefeed output:
    {
    new_val: null,
    old_val: {
    id: '362ae837-2e29-4695-adef-4fa415138f90',
    name: 'Bob',
    ...
    }
    }
    Changefeeds

    View Slide

  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

    View Slide

  12. Building the backend with
    RethinkDB and Sinatra

    View Slide

  13. Backend
    • Running on Thin for
    EventMachine support
    • Sinatra for API endpoints and
    serving resources
    • Faye WebSockets for realtime
    messaging

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  17. Ruby to JavaScript with the
    Opal transpiler project

    View Slide

  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

    View Slide

  19. Why Opal?
    • Use one language consistently
    throughout your project
    • Reuse (some) existing code
    • Ruby is powerful and expressive,
    well-suited for many tasks

    View Slide

  20. But Why?
    BECAUSE I CAN

    View Slide

  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

    View Slide

  22. Why Not Opal?
    seriously crazy tracebacks

    View Slide

  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")

    View Slide

  24. Assets
    Drop $opalinit in a tag<br/>!!!<br/>%html<br/>%head<br/>%title Test<br/>%script(src="/assets/main.js")<br/>%script= $opalinit<br/>%body<br/>

    View Slide

  25. Building the frontend with
    React.rb components

    View Slide

  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

    View Slide

  27. React.rb
    class App
    include React::Component
    def render
    h1 { "Hello, world!" }
    end
    end
    Defining a React.rb component

    View Slide

  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

    View Slide

  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

    View Slide

  30. The Stack
    RethinkDB Thin
    Sinatra
    Faye WS
    Opal
    WS Client
    React.rb
    Ruby Client
    STORAGE BACKEND FRONTEND

    View Slide

  31. Additional Resources
    • RethinkDB website:

    http://rethinkdb.com
    • Opal website:

    http://opalrb.org
    • React.rb project:

    https://github.com/zetachang/
    react.rb

    View Slide