Notifications usually work behind the scenes, so they don’t typically include much in the way of error handling for users.
Currently, we try to push notifications and silently handle most errors:
# app/models/web_push_subscription.rb
class WebPushSubscription < ApplicationRecord
# …
def deliver_payload(data)
WebPush.payload_send(
message: data.to_json,
endpoint: endpoint,
p256dh: p256dh,
auth: auth,
vapid: {
public_key: ENV.fetch("VAPID_PUBLIC"),
private_key: ENV.fetch("VAPID_PRIVATE")
}
)
rescue WebPush::ExpiredSubscription
Rails.logger.info "Removing expired WebPush subscription"
destroy
rescue WebPush::Unauthorized
Rails.logger.info "Removing unauthorized WebPush subscription"
destroy
end
end
This approach works well for simply pushing notifications. However, if we want to build a user-facing interface for managing notifications, we need to expose more details about delivery success or failure.
We can follow the pattern of ActiveRecord’s save
method to update deliver_payload
so it returns whether the delivery was successful and includes a delivery_error
attribute if an error occurs.
# app/models/web_push_subscription.rb
class WebPushSubscription < ApplicationRecord
attr_reader :delivery_error
# …
def deliver_payload(data)
WebPush.payload_send(
message: data.to_json,
endpoint: endpoint,
p256dh: p256dh,
auth: auth,
vapid: {
public_key: ENV.fetch("VAPID_PUBLIC"),
private_key: ENV.fetch("VAPID_PRIVATE")
}
)
@delivery_error = nil
rescue WebPush::ExpiredSubscription
@delivery_error = "Removing expired WebPush subscription"
destroy
rescue WebPush::Unauthorized
@delivery_error = "Removing unauthorized WebPush subscription"
destroy
ensure
if @delivery_error
Rails.logger.warn @delivery_error
false
else
true
end
end
end
With these updates, we can now determine whether a notification was successfully delivered or identify specific errors when something goes wrong.
Tomorrow, we’ll build on this to create a user-facing interface for testing notifications.