ARTICLE AD BOX
Using Webpush gem.
I generated vapid keys. I saved them as environment variables. And I put the public key in a meta tag. Then I register my service worker. I wrote a function to ask client for permission to notify him. I call the function when client clicks on a button. When client grants permission for push notifications, I subscribe him with vapid public key and save his subscription through axios to the server. // application.js import axios from 'axios' const api = axios.create({ baseURL: `/`, headers: { 'X-CSRF-Token': document.head.querySelector('meta[name=csrf-token]') ?.content, Accept: 'applicaton/json' } }) const vapidPublicKey = document.querySelector( 'meta[name="vapid-public-key"]', ).content; if ('serviceWorker' in navigator) window.addEventListener('load', () => navigator.serviceWorker.register('/service-worker.js')); async function onPushSubscribe() { await Notification.requestPermission() const subscription = await subscribe() const { endpoint, keys: { p256dh, auth }, } = subscription.toJSON(); api.post('/push_subscriptions', { push_subscription: { endpoint, p256dh_key: p256dh, auth_key: auth } }) } const subscribe = async () => { const registration = await navigator.serviceWorker.ready; let subscription = await registration.pushManager.getSubscription(); if (!subscription) { subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: vapidPublicKey, }); if (!subscription) console.error('Web push subscription failed'); } return subscription; };Here I save the subscription in the database through a model:
class PushSubscriptionsController < ApplicationController def create begin PushSubscription.create!(push_subscription_params) head :ok rescue => e render json: { error: e.message }, status: :unprocessable_entity end end private def push_subscription_params params.expect(push_subscription: [:endpoint, :p256dh_key, :auth_key ]) end endThen I can finally send a push notfication.
@subscription = PushSubscription.last # For example message = { title: 'New message', options: { body: 'Hello...', image: 'url-to-image', data: { path: 'url-to-message' }, icon: 'url-to-icon', badge: 'url-to-icon', lang: I18n.locale, vibrate: [ 200, 100, 200 ] } } begin WebPush.payload_send( message: message.to_json, endpoint: @subscription['endpoint'], p256dh: @subscription['keys']['p256dh'], auth: @subscription['keys']['auth'], vapid: { subject: "mailto:[email protected]", public_key: ENV['VAPID_PUBLIC_KEY'], private_key: ENV['VAPID_PRIVATE_KEY'] } ) rescue WebPush::InvalidSubscription # If the subscription is invalid or expired, delete it from the database @subscription.destroy rescue => e Rails.logger.error "WebPush failed for #{subscription.id}: #{e.message}" end