How to Implement Web Push Notifications in Ruby on Rails (From Scratch!)

How to Implement Web Push Notifications in Ruby on Rails (From Scratch!)

Ever felt like your users just need a gentle nudge—or maybe a not-so-gentle reminder—that you still exist? Well, web push notifications are your new best friend! They’re like little love notes from your app, popping up to say, “Hey, don’t forget about me!” And the best part? Your users don’t even need to be on your site. Today, we’re diving into how you can sprinkle this magic into your Rails app, step by step. And yes, we’ll be throwing in some code—real, working code—because we’re not just here to chat. Ready? Let’s rock and roll! 🛠️

Step 1: Setting Up Your Rails App

First things first—make sure you have a Rails app that’s ready to receive some serious love. If you’re starting from scratch (and who doesn’t love a fresh start?):

rails new push_notifier
cd push_notifier        

Once your app is up and running, let’s add the secret sauce:

# Gemfile
gem 'web-push'
gem 'serviceworker-rails'        

Now, give bundle install a whirl and let those gems sparkle!

Step 2: Generate Your VAPID Keys

VAPID keys are like your app’s official badge. Without them, your notifications are just rogue agents, wandering the web without a purpose.

# Run this in your terminal
vapid_key = WebPush.generate_key
puts "VAPID Public Key: #{vapid_key.public_key}"
puts "VAPID Private Key: #{vapid_key.private_key}"        

Pro tip: Keep these keys somewhere safe—preferably not scribbled on a Post-it. They’re the keys to the kingdom!

Step 3: Setting Up the Database Tables

Alright, let’s talk data. You need to have a place to store all this web-push goodness. This isn’t just a fling; we’re building something that lasts!

3.1 Create the subscriptions Table

To store user subscriptions, let’s create a table. Think of it as our little black book for push notifications

rails generate migration CreateSubscriptions        

Now, let’s lay down the structure in the generated migration file:

# db/migrate/[timestamp]_create_subscriptions.rb
class CreateSubscriptions < ActiveRecord::Migration[6.1]
  def change
    create_table :subscriptions do |t|
      t.references :user, null: false, foreign_key: true
      t.text :endpoint, null: false
      t.text :p256dh_key, null: false
      t.text :auth_key, null: false

      t.timestamps
    end

    add_index :subscriptions, :endpoint, unique: true
  end
end        

Explanation (With a Side of Sass):

  • user_id: Links the subscription to a user, because no one wants anonymous love notes, right?
  • endpoint: The URL where you send your notifications. It’s like having a direct line to your user’s attention.
  • p256dh_key: A public key—think of it as the handshake before the dance.
  • auth_key: A secret shared between your app and the browser, making sure no one crashes the party.
  • timestamps: Automatically adds created_at and updated_at fields, because history matters!

Now, let’s make it official:

rails db:migrate        

Step 4: Setting Up the Service Worker

Your service worker is the unsung hero of this whole operation. It’s the one that actually handles the notifications when they come in. Think of it as your app’s butler, ready to deliver messages with a bow.

// app/assets/javascripts/serviceworker.js
self.addEventListener('push', function(event) {
  const data = event.data.json();
  self.registration.showNotification(data.title, {
    body: data.message,
    icon: '/path-to-your-icon.png'
  });
});        

And don’t forget to let Rails know who’s handling the butler duties:

# config/initializers/serviceworker.rb
Rails.application.config.serviceworker.routes.draw do
  match "/serviceworker.js"
end        

Step 5: Frontend Magic (Subscribing to Notifications)

Now let’s convince your users to subscribe. It’s like asking someone to follow you on social media, except way cooler. Here’s how you can do it:

// app/assets/javascripts/application.js

navigator.serviceWorker.register('/serviceworker.js')
  .then(function(registration) {
    console.log('Service Worker registered with scope:', registration.scope);
    return registration.pushManager.getSubscription()
      .then(function(subscription) {
        if (subscription === null) {
          // No subscription, time to charm the user
          return registration.pushManager.subscribe({
            userVisibleOnly: true,
            applicationServerKey: 'Your_VAPID_Public_Key'
          });
        }
        return subscription;
      });
  })
  .then(function(subscription) {
    console.log('User is subscribed:', subscription);
    // Time to seal the deal
  })
  .catch(function(error) {
    console.error('Oops! Something went wrong:', error);
  });        

Once subscribed, your app needs to save this valuable relationship:

function sendSubscriptionToServer(subscription) {
  fetch('/subscriptions', {
    method: 'POST',
    body: JSON.stringify({
      subscription: subscription.toJSON()
    }),
    headers: {
      'Content-Type': 'application/json',
      'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
    }
  });
}        

Step 6: Handling Subscriptions on the Backend

Your users have said “yes” to notifications. Time to make it official on the backend.

6.1 Creating the Subscription Model

In case you skipped the previous section (you rebel), here’s how to generate the model:

rails generate model Subscription user:references endpoint:text p256dh_key:text auth_key:text        

6.2 Creating the Subscriptions Controller

Now, let’s create a controller to manage these relationships:

# app/controllers/subscriptions_controller.rb
class SubscriptionsController < ApplicationController
  def create
    subscription_params = params.require(:subscription).permit(:endpoint, :p256dh_key, :auth_key)
    current_user.subscriptions.create(subscription_params)

    render json: { message: "Subscription created successfully" }, status: :created
  end

  def destroy
    subscription = current_user.subscriptions.find_by(endpoint: params[:endpoint])
    subscription.destroy if subscription

    render json: { message: "Subscription deleted successfully" }, status: :ok
  end
end        

Step 7: Sending Notifications from Your Rails App

Now that your users are all in, let’s send them something fun!

# app/controllers/notifications_controller.rb
class NotificationsController < ApplicationController
  def create
    subscription = current_user.subscriptions.find(params[:subscription_id])
    message = {
      title: 'Greetings from Rails!',
      message: 'You just got a push notification. How cool is that?'
    }

    WebPush.payload_send(
      endpoint: subscription.endpoint,
      message: JSON.generate(message),
      p256dh: subscription.p256dh_key,
      auth: subscription.auth_key,
      vapid: {
        subject: 'mailto:your-email@example.com',
        public_key: ENV['VAPID_PUBLIC_KEY'],
        private_key: ENV['VAPID_PRIVATE_KEY']
      }
    )

    render json: { message: "Notification sent successfully" }, status: :ok
  end
end        

Step 8: Testing It Out

Ready for the moment of truth? Fire up your Rails server, visit your site, and hit that subscribe button. Then trigger a notification and watch the magic unfold!

rails server        

Final Thoughts

And there you have it! You’ve just implemented web push notifications in your Rails app from scratch, with a little bit of sass and a whole lot of code. Now, your users can receive your love notes even when they’re off doing other things. How awesome is that? 😎

If you enjoyed this guide or have any questions, drop a comment below. Let’s keep the conversation going—your thoughts might just inspire my next article!

#Rails #WebPush #Notifications #RubyOnRails #CodingIsFun

To view or add a comment, sign in

More articles by David Raja

Others also viewed

Explore content categories