Using RethinkDB in Rails with ActionCable

Let’s check how we can implement RethinkDB with ActionCable into Ruby on Rails application.

You can find all code in rethinkdb_example.

First of all, let’s create sample app with rails command:

rails new rethinkdb_example

And setup ActionCable route in routes.rb:

Rails.application.routes.draw do
  mount ActionCable.server => '/cable'

We need to generate channel for active users:

rails g channel active_users

Let’s generate controller and set it to the root in routes.rb

rails g controller tasks index

Now, moving to RethinkDB.

RethinkDB is a document oriented data store much like MongoDB, but with some key advantages.

RethinkDB makes building and scaling realtime apps dramatically easier. Get started by installing the server, and jump into our getting started guide to start building your first app in minutes.

You can read more here.

Let’s integrate RethinkDB into our rails application.

We need two gems.

gem 'nobrainer'
gem 'nobrainer_streams' 

Run bundle and installer script, to have your application use NoBrainer instead of ActiveRecord.

bundle && rails g nobrainer:install

Now, if you generate model User with rails g model User it will look like:

class User
  include NoBrainer::Document
  include NoBrainer::Document::Timestamps

Now, let’s move to our ActiveUsersChannel. Here we have subscribed and unsubscribed methods.

They’re just calling then somebody open or close connection.

class ActiveUsersChannel < ApplicationCable::Channel
  include NoBrainer::Streams

  def subscribed
    @user = User.create
    stream_from User.all, include_initial: true

  def unsubscribed

Now, let’s change our tasks/index.html.erb we add here special div with active_users_list ID.

<section id="active_users">
  <h2>Active users</h2>
  <ul id="active_users_list">

Now let’s take a look into generated file:

App.active_users = App.cable.subscriptions.create "ActiveUsersChannel",
  connected: ->
    # Called when the subscription is ready for use on the server

  disconnected: ->
    # Called when the subscription has been terminated by the server

  received: (data) ->
    # Called when there's incoming data on the websocket for this channel

A little change here, for now just keep received event:

App.active_users = App.cable.subscriptions.create "ActiveUsersChannel",
  received: (data) ->
    if data.old_val && !data.new_val
    else if data.new_val

Just update our ul by ID and add new data:

App.spreadsheet =
  active_users: {}

  new_user: (user) ->
    @active_users[] = user

  remove_user: (user) ->
    delete @active_users[]

  render_active_users: () ->
      ("<li>#{}</li>" for id,user of @active_users).join("")

Now you can open browser window, then open second one, so you can see how new user will be added to the list. Or deleted - if you close browser.