Setting up Service Worker in Ruby on Rails

Webworkers are most promising future of HTML5, get your Rails app ready.

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction.

Service workers are isolated browser threads running in the background, in an entirely different context from the web page and therefore have no access to the DOM, the window or document object. 

We have been using Service Workers on Pasilobus apps for some time now. Using service workers, we can intercept requests made by server at the browser level and trigger different actions or even serve a cached version of your app and users never get disconnected.

Service workers also allow for background sync, so even if the internet connection is lost, using service workers, your app can still process the data and sync back to the server as soon as the connection is restored. 

Adding a service worker to a Rails app is easy. Start making a controller for it

class ServiceworkerController < ApplicationController
  layout false

  def service_worker
  end
end

Then let's add a route for our service worker

 # Service Worker
 get '/service-worker.js' => "serviceworker#service_worker"

To call the service worker, we need to add a script to the asset pipeline, if you are using Rails 6 this should go to webpack and javascript folder:

# javascript/src/service_worker.js

// Use feature-detection to check for ES6 support.
function browserSupportsES6() {
  try { eval("var foo = (x)=>x+1"); }
  catch (e) { return false; }
  return true;
}

// Use service workers only if the browser supports ES6,
// the Cache API and of course Service Workers themselves.
if (browserSupportsES6() && ('caches' in window) && ('serviceWorker' in navigator)) {
  navigator.serviceWorker.register('/service-worker.js', { scope: '/' })
  .then(function(reg) {
     //console.log('Service worker registration succeeded!');
  }).catch(function(error) {
     //console.log('Service worker registration failed: ' + error);
  });
}

# javascript/packs/application.js 

import "src/service_worker.js"

This will register our service worker as soon as the user opens the app in browser. 

And of course create a view file for the actual worker 

# views/serviceworker/service_worker.js.erb 

var CACHE_VERSION = 'v1';
var CACHE_NAME = CACHE_VERSION + ':sw-cache-APPNAME';


function onInstall(event) {
  // console.log('[Serviceworker]', "Installing!", event);
  event.waitUntil(
    caches.open(CACHE_NAME).then(function prefill(cache) {
      return cache.addAll([
        '<%= asset_pack_path 'application.js' %>',
        '<%= asset_pack_path 'application.css' %>',
        '/offline.html'
      ]);
    })
  );
}

self.addEventListener('install', onInstall);

Our simple worker contains a function that is trigger on install event, and it tells the browser to cache assets and offline.html sample page that will be serve to the user when the connection is lost.

Let's also add our offline.html file 

# views/errors/offline.html.erb 

<h1>Hey I am page served by service worker.js<h1>

Service workers expire after a period of time, hence if you ever change the file, browsers will update service worker automatically.

When developing with service workers. Remember to disable them in the browser so they will not interfere with your work.

And that's all. Get started with workers and serve an custom offline warning page for your users.

Related Articles

Working without boundaries: How to communicate while working remotely?

Night at the VR Shopping Museum