Noticed

repository·main·Indexed 25 days ago

https://github.com/excid3/noticed

A Ruby on Rails gem for sending various types of notifications (Email, SMS, Slack, etc.) to recipients using individual and bulk delivery patterns. It supports a wide range of delivery methods including ActionCable, Firebase Cloud Messaging, Microsoft Teams, Discord, and Bluesky, and provides tools for creating custom delivery methods, managing notification records, and implementing conditional delivery logic.

Tokens
16.1K
Snippets
57
Records
85
Agent score
82%

What's inside noticed

  1. Overview of Noticed delivery methods

    main

    Noticed supports two top-level types of delivery methods:

    1. Individual Deliveries: Each recipient receives their own unique notification. This is used when different recipients need different information related to the same event (e.g., a buyer receiving contract details while a salesperson receives commission details).
    2. Bulk Deliveries: A single notification is sent to all recipients. This is typically used for pushing updates to external platforms where users are managed (e.g., Slack or Discord) to notify a group of people with the same content.

    Supported Individual Delivery Methods

    • ActionCable
    • Action Push Native
    • Apple Push Notification Service
    • Email
    • Firebase Cloud Messaging (iOS, Android, and web clients)
    • Microsoft Teams
    • Slack
    • Twilio Messaging (SMS, Whatsapp)
    • Vonage SMS
    • Test

    Supported Bulk Delivery Methods

    • Bluesky
    • Discord
    • Slack
    • Webhook
  2. Configure Email Delivery Method

    main

    Use the deliver_by :email block to configure how notifications are sent via email. You must specify the mailer and the method to be called on that mailer. You can also provide custom params, positional args, or keyword kwargs via lambdas.

    By default, config.enqueue is false because Noticed already handles deliveries in separate jobs. Set config.enqueue = true only if you explicitly want to use deliver_later to queue the email via ActiveJob.

    deliver_by :email do |config|
      config.mailer = "UserMailer"
      config.method = :invoice_paid
      config.params = ->{ params }
      config.args = ->{ [1, 2, 3] }
      config.kwargs = ->{ {body: "Hey there", subject: "Thanks for joining"} }
    
      # Enqueues a separate job for sending the email using deliver_later.
      # config.enqueue = false
    end
  3. Configure Twilio Messaging delivery method

    main

    Use the deliver_by :twilio_messaging block to send SMS or WhatsApp messages via Twilio. You can customize the JSON payload, provide credentials, and specify the API URL.

    By default, the payload uses params[:message] for the body, credentials from Rails.application.credentials.twilio, and the Twilio Messages API URL.

    deliver_by :twilio_messaging do |config|
      config.json = -> {
        {
           From: "+1234567890",
           To: recipient.phone_number,
           ContentSid: "value", # Template SID
           ContentVariables: {1: recipient.first_name}
        }
      }
    end
  4. Use the Test delivery method for notifications

    main

    The :test delivery method allows you to save deliveries in memory instead of sending them via a real transport (like email or SMS). This is useful for testing notification logic in your test suite.

    To use it, add deliver_by :test to your notifier class. You can then inspect all deliveries sent during the session using Noticed::DeliveryMethods::Test.delivered.

    class CommentNotification
      deliver_by :test
    end
    
    # To inspect delivered notifications:
    Noticed::DeliveryMethods::Test.delivered #=> []
  5. Use ActionCable to deliver notifications via WebSockets

    main

    You can deliver notifications to the browser in real-time using the :action_cable delivery method. This allows you to broadcast notification data directly to an ActionCable channel.

    Configure the delivery method within your notification class using the deliver_by block.

    deliver_by :action_cable do |config|
      config.channel = "Noticed::NotificationChannel"
      config.stream = ->{ recipient }
      config.message = ->{ params.merge( user_id: recipient.id) }
    end
  6. Implement fallback notifications with wait and conditional options

    main

    You can implement a pattern where a notification is sent via a real-time service first, and then sent via email if the user hasn't read it after a certain period. This is achieved by combining multiple deliver_by calls with the wait and if/unless options.

    Note: You must manually call the #mark_as_read method on the notification in your application logic for the unless condition to work.

    class NewCommentNotifier < Noticed::Event
      deliver_by :action_cable
      deliver_by :email do |config|
        config.mailer = "CommentMailer"
        config.wait = 15.minutes
        config.unless = -> { read? }
      end
    end
  7. Configure the iOS delivery method

    main

    To use iOS notifications, define a deliver_by :ios block within your ApplicationNotifier. You must provide authentication credentials (bundle identifier, key ID, team ID, and the p8 key content) and a way to retrieve device tokens.

    Note: This delivery method is deprecated. Please use Action Push Native instead.

    class CommentNotifier < ApplicationNotifier
      deliver_by :ios do |config|
        config.device_tokens = -> { recipient.notification_tokens.where(platform: :iOS).pluck(:token) }
        config.format = ->(apn) {
          apn.alert = "Hello world"
          apn.custom_payload = {url: root_url(host: "example.org")}
        }
        config.bundle_identifier = Rails.application.credentials.dig(:ios, :bundle_id)
        config.key_id = Rails.application.credentials.dig(:ios, :key_id)
        config.team_id = Rails.application.credentials.dig(:ios, :team_id)
        config.apns_key = Rails.application.credentials.dig(:ios, :apns_key)
        config.error_handler = ->(exception) { ... }
      end
    end
  8. Handle Twilio Messaging errors

    main

    You can implement custom error handling for Twilio delivery failures using the error_handler option. The handler receives a twilio_error_response object. You can parse the response body to inspect Twilio error codes (e.g., 21211 for an invalid 'To' number) and decide how to react.

    deliver_by :twilio_messaging do |config|
      config.error_handler = lambda do |twilio_error_response|
        error_hash = JSON.parse(twilio_error_response.body)
        case error_hash["code"]
        when 21211
          # The 'To' number is not a valid phone number.
          # Write your error handling code
        else
          raise "Unhandled Twilio error: #{error_hash}"
        end
      end
    end
  9. Update iOS app badges

    main

    You can manage the iOS app badge by setting the badge property on the notification object within the format block.

    To update the badge in the background without showing an alert (e.g., when a user marks a notification as read), set apn.alert = nil.

    Using Noticed::Ephemeral is recommended for badge-only updates to avoid unnecessary database writes.

    class NativeBadgeNotifier < Noticed::Ephemeral
      deliver_by :ios do |config|
        config.format = ->(apn) {
          # Setting the alert text to nil delivers the notification in the background
          apn.alert = nil
          apn.custom_payload = {}
          apn.badge = recipient.notifications.unread.count
        }
      end
    end
    
    # Usage:
    notification.mark_as_read!
    NativeBadgeNotifier.with(record: notification).deliver(notification.recipient)
    class NativeBadgeNotifier < Noticed::Ephemeral
      deliver_by :ios do |config|
        config.format = ->(apn) {
          # Setting the alert text to nil will deliver the notification in
          # the background. This is used to update the app badge on the iOS home screen
          apn.alert = nil
          apn.custom_payload = {}
          apn.badge = recipient.notifications.unread.count
        }
      end
    end
  10. Use the Bluesky bulk delivery method

    main

    You can use the :bluesky bulk delivery method to create posts on Bluesky from your notifications. Within the bulk_deliver_by :bluesky block, you must provide an identifier (your username), a password, and a json lambda that returns the post payload.

    The json payload should include:

    • text: The content of the post.
    • createdAt: The timestamp of the post in ISO8601 format.
    class CommentNotification
      bulk_deliver_by :bluesky do |config|
        config.identifier = "username"
        config.password = "password"
        config.json = -> {
          {
            text: "Hello world!",
            createdAt: Time.current.iso8601
            # ...
          }
        }
      end
    end