Setting Up Push Notifications in Rails

1. Installing Web Push Gem

Rails does not have built-in support for push notifications, so we use the web-push gem:

bundle add web-push

Next, generate VAPID (Voluntary Application Server Identification) keys, which authenticate push requests:

webpush generate_key

This outputs a public and private key. Add them to config/secrets.yml:

development:
  vapid_public_key: "YOUR_PUBLIC_KEY"
  vapid_private_key: "YOUR_PRIVATE_KEY"

2. Setting Up Subscription Endpoints

In the Rails backend, create an API endpoint to store push subscriptions. This will handle incoming subscription data from the frontend, which typically includes the endpoint URL and encryption keys.

class PushSubscriptionsController < ApplicationController
  def create
    subscription = PushSubscription.find_or_initialize_by(endpoint: params[:endpoint])
    subscription.update!(keys: params[:keys].to_json)
    render json: { message: "Subscribed successfully" }
  end
end

And define the route in config/routes.rb:

post "/push_subscriptions", to: "push_subscriptions#create"

Now, when a user subscribes, their subscription details will be stored in the database for future use.


3. Creating the PushSubscription Model

In section 2, we are using the PushSubscription model to store the subscription data. However, the web-push gem does not automatically create this model for you. You’ll need to create the model manually.

Follow these steps to set up the PushSubscription model:

3.1. Generate the Model

First, generate the PushSubscription model using the Rails generator. This model will store the endpoint (the URL to which notifications are sent) and the keys (encryption keys for the subscription).

rails generate model PushSubscription endpoint:string keys:text

This will create the necessary migration file and a model file at app/models/push_subscription.rb.

3.2. Run the Migration

After generating the model, run the migration to create the push_subscriptions table in the database:

rails db:migrate

3.3. The PushSubscription Model

Next, open the generated model file app/models/push_subscription.rb. You can define validations or any additional logic, but here’s a simple version of the model:

class PushSubscription < ApplicationRecord
  # Add any necessary validations here, for example:
  validates :endpoint, presence: true
  validates :keys, presence: true
end

This model will now be used to store the subscription data coming from the frontend.

3.4. Updating the Controller

The PushSubscriptionsController we wrote earlier will now be able to interact with the PushSubscription model to save subscription data.

Here’s the PushSubscriptionsController code again for reference:

class PushSubscriptionsController < ApplicationController
  def create
    subscription = PushSubscription.find_or_initialize_by(endpoint: params[:endpoint])
    subscription.update!(keys: params[:keys].to_json)
    render json: { message: "Subscribed successfully" }
  end
end

4. Sending Notifications from Rails

Once the subscriptions are stored in the database, we can send push notifications.

The web-push gem allows us to send push notifications to all stored subscriptions.

We can set this up in a background job or through a simple controller action.

To send a notification, modify PushNotificationsController:

require "webpush"

class PushNotificationsController < ApplicationController
  def send_notification
    subscription = PushSubscription.last
    payload = { title: "New Update!", body: "Check out the latest features!" }

    Webpush.payload_send(
      message: payload.to_json,
      endpoint: subscription.endpoint,
      p256dh: JSON.parse(subscription.keys)["p256dh"],
      auth: JSON.parse(subscription.keys)["auth"],
      vapid: {
        public_key: Rails.application.credentials.dig(:vapid_public_key),
        private_key: Rails.application.credentials.dig(:vapid_private_key)
      }
    )

    render json: { message: "Notification sent!" }
  end
end

Now, we can trigger notifications using:

curl -X POST http://localhost:3000/send_notification

This way, we can send notifications to all the users who have subscribed.

By following these steps, we'll have a complete push notification system set up with Rails using the web-push gem.

The PushSubscription model stores the necessary data, and the controller is ready to handle the subscription process and send notifications when needed.