Registering and Installing a Service Worker in Rails

To use a service worker in a Rails application, we need to follow a structured approach:

  1. Create a service worker file to define caching behavior and event listeners.
  2. Register the service worker in the front-end code.
  3. Ensure Rails serves the service worker file correctly.

By integrating service workers, a Rails PWA can intercept network requests, cache assets, and provide an offline experience.

1. Creating the Service Worker File in Rails

In a Rails application, service workers should be stored in the app/assets/javascripts or app/javascript directory, depending on whether the app uses the asset pipeline or Webpacker/esbuild.

Basic Service Worker Script

Create a new file:

touch app/javascript/service_worker.js

Now, open service_worker.js and define basic event listeners:

const CACHE_NAME = "rails-pwa-cache-v1";
const ASSETS_TO_CACHE = [
  "/",
  "/offline.html",
  "/assets/logo.png",
];

self.addEventListener("install", (event) => {
  console.log("Service Worker installing...");
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(ASSETS_TO_CACHE);
    })
  );
});

self.addEventListener("activate", (event) => {
  console.log("Service Worker activated.");
  event.waitUntil(self.clients.claim());
});

This service worker:

2. Registering the Service Worker in Rails

Once the service worker script is created, it must be registered in the browser so that it runs when the PWA is loaded.

Modify app/javascript/packs/application.js (or app/assets/javascripts/application.js if using Sprockets):

if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/service_worker.js")
      .then((registration) => {
        console.log("Service Worker registered with scope:", registration.scope);
      })
      .catch((error) => {
        console.error("Service Worker registration failed:", error);
      });
  });
}

This code:

3. Serving the Service Worker in Rails

By default, Rails does not serve JavaScript files from the app/javascript directory as static assets. To ensure the service worker is accessible, we must explicitly serve it through a controller.

Adding a Route for the Service Worker

Modify config/routes.rb:

get "/service_worker.js", to: "service_worker#show"

Creating the Controller to Serve the File

Generate a new controller:

rails g controller ServiceWorker

Modify app/controllers/service_worker_controller.rb:

class ServiceWorkerController < ApplicationController
  def show
    response.headers["Service-Worker"] = "script"
    render file: Rails.root.join("app/javascript/service_worker.js"), content_type: "application/javascript"
  end
end

Ensuring Rails Includes the Service Worker File in Precompilation

If using the asset pipeline, add the following to config/initializers/assets.rb:

Rails.application.config.assets.precompile += %w[service_worker.js]

4. Testing the Service Worker

1. Start the Rails server:

rails s
  1. Open the browser and go to Developer Tools > Application > Service Workers.
  2. If registered successfully, you will see service_worker.js running.
  3. Try disabling your internet and refreshing the page—cached resources should still load.

Now, the Rails application has a registered and running service worker. Next, we’ll explore handling service worker events for better caching and offline support.