Action Push Native is a Rails push notification gem for mobile platforms, supporting APNs (Apple) and FCM (Google).
1. bundle add action_push_native 2. bin/rails g action_push_native:install 3. bin/rails action_push_native:install:migrations 4. bin/rails db:migrateThis will install the gem and run the necessary migrations to set up the database.
The installation will create:
app/models/application_push_notification.rbapp/jobs/application_push_notification_job.rbapp/models/application_push_device.rbconfig/push.yml
app/models/application_push_notification.rb:
class ApplicationPushNotification < ActionPushNative::Notification # Set a custom job queue_name queue_as :realtime # Controls whether push notifications are enabled (default: !Rails.env.test?) self.enabled = Rails.env.production? # Define a custom callback to modify or abort the notification before it is sent before_delivery do |notification| throw :abort if Notification.find(notification.context[:notification_id]).expired? end endUsed to create and send push notifications. You can customize it by subclassing or you can change the application defaults by editing it directly.
app/jobs/application_push_notification_job.rb:
class ApplicationPushNotificationJob < ActionPushNative::NotificationJob # Enable logging job arguments (default: false) self.log_arguments = true # Report job retries via the `Rails.error` reporter (default: false) self.report_job_retries = true endJob class that processes the push notifications. You can customize it by editing it directly in your application.
app/models/application_push_device.rb:
class ApplicationPushDevice < ActionPushNative::Device # Customize TokenError handling (default: destroy!) # rescue_from (ActionPushNative::TokenError) { Rails.logger.error("Device #{id} token is invalid") } endThis represents a push notification device. You can customize it by editing it directly in your application.
config/push.yml:
shared: apple: # Token auth params # See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :key_id) %> encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :encryption_key)&.dump %> team_id: your_apple_team_id # Your identifier found on https://developer.apple.com/account/resources/identifiers/list topic: your.bundle.identifier google: # Your Firebase project service account credentials # See https://firebase.google.com/docs/cloud-messaging/auth-server encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :encryption_key)&.dump %> # Firebase project_id project_id: your_project_idThis file contains the configuration for the push notification services you want to use. The push notification services supported are apple (APNs) and google (FCM). If you're configuring more than one app, see the section Configuring multiple apps below.
You can send push notifications to multiple apps using different notification classes. Each notification class need to inherit from ApplicationPushNotification and set self.application, to a key set in push.yml for each supported platform. You can also (optionally) set a shared application option in push.yml. This acts as the base configuration for that platform, and its values will be merged (and overridden) with the matching app-specific configuration.
In the example below we are configuring two apps: calendar and email using respectively the CalendarPushNotification and EmailPushNotification notification classes.
class CalendarPushNotification < ApplicationPushNotification self.application = "calendar" # Custom notification logic for calendar app end class EmailPushNotification < ApplicationPushNotification self.application = "email" # Custom notification logic for email app endshared: apple: # Base configuration for Apple platform # This will be merged with the app-specific configuration application: team_id: your_apple_team_id calendar: # Token auth params # See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :calendar, :key_id) %> encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :calendar, :encryption_key)&.dump %> # Your identifier found on https://developer.apple.com/account/resources/identifiers/list topic: calendar.bundle.identifier email: # Token auth params # See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :email, :key_id) %> encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :email, :encryption_key)&.dump %> # Your identifier found on https://developer.apple.com/account/resources/identifiers/list topic: email.bundle.identifier google: calendar: # Your Firebase project service account credentials # See https://firebase.google.com/docs/cloud-messaging/auth-server encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :calendar, :encryption_key)&.dump %> # Firebase project_id project_id: calendar_project_id email: # Your Firebase project service account credentials # See https://firebase.google.com/docs/cloud-messaging/auth-server encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :email, :encryption_key)&.dump %> # Firebase project_id project_id: email_project_iddevice = ApplicationPushDevice.create! \ name: "iPhone 16", token: "6c267f26b173cd9595ae2f6702b1ab560371a60e7c8a9e27419bd0fa4a42e58f", platform: "apple" notification = ApplicationPushNotification.new \ title: "Hello world!", body: "Welcome to Action Push Native" notification.deliver_later_to(device)deliver_later_to supports also an array of devices:
notification.deliver_later_to([ device1, device2 ])A notification can also be delivered synchronously using deliver_to:
notification.deliver_to(device)It is recommended to send notifications asynchronously using deliver_later_to. This ensures error handling and retry logic are in place, and avoids blocking your application's execution.
You can pass custom data to the application using the with_data method:
notification = ApplicationPushNotification .with_data({ badge: "1" }) .new(title: "Welcome to Action Push Native")You can configure custom platform payload to be sent with the notification. This is useful when you need to send additional data that is specific to the platform you are using.
You can use with_apple for Apple and with_google for Google:
notification = ApplicationPushNotification .with_apple(aps: { category: "observable", "thread-id": "greeting"}, "apns-priority": "1") .with_google(data: { badge: 1 }) .new(title: "Hello world!")The platform payload takes precedence over the other fields, and you can use it to override the default behaviour:
notification = ApplicationPushNotification .with_google(android: { notification: { notification_count: nil } }) .new(title: "Hello world!", body: "Welcome to Action Push Native", badge: 1)This will unset the default notification_count (badge) field in the Google payload, while keeping title and body.
You can create a silent notification via the silent method:
notification = ApplicationPushNotification.silent.with_data(id: 1).newThis will create a silent notification for both Apple and Google platforms and sets an application data field of { id: 1 } for both platforms. Silent push notification must not contain any attribute which would trigger a visual notification on the device, such as title, body, badge, etc.
A Device can be associated with any record in your application via the owner polymorphic association:
user = User.find_by_email_address("jacopo@37signals.com") ApplicationPushDevice.create! \ name: "iPhone 16", token: "6c267f26b173cd9595ae2f6702b1ab560371a60e7c8a9e27419bd0fa4a42e58f", platform: "apple", owner: userYou can specify Active Record like callbacks for the delivery method. For example, you can modify or cancel the notification by specifying a custom before_delivery block. The callback has access to the notification object. You can also pass additional context data to the notification by adding extra arguments to the notification constructor:
class CalendarPushNotification < ApplicationPushNotification before_delivery do |notification| throw :abort if Calendar.find(notification.context[:calendar_id]).expired? end end data = { calendar_id: @calendar.id, identity_id: @identity.id } notification = CalendarPushNotification .with_apple(data) .with_google(data: data) .new(calendar_id: 123) notification.deliver_later_to(device)If using the default ApplicationPushDevice model does not fit your needs, you can create a custom device model, as long as:
- It can be serialized and deserialized by
ActiveJob. - It responds to the
tokenandplatformmethods. - It implements a
pushmethod like this:
class CustomDevice # Your custom device attributes and methods... def push(notification) notification.token = token ActionPushNative.service_for(platform, notification).push(notification) rescue ActionPushNative::TokenError => error # Custom token error handling end end| Name | Description |
|---|---|
| :title | The title of the notification. |
| :body | The body of the notification. |
| :badge | The badge number to display on the app icon. |
| :thread_id | The thread identifier for grouping notifications. |
| :sound | The sound to play when the notification is received. |
| :high_priority | Whether the notification should be sent with high priority (default: true). |
| :google_data | The Google-specific payload for the notification. |
| :apple_data | The Apple-specific payload for the notification. It can also be used to override APNs request headers, such as apns-push-type, apns-priority, etc. |
| :data | The data payload for the notification, sent to all platforms. |
| ** | Any additional attributes passed to the constructor will be merged in the context hash. |
| Name | Description |
|---|---|
| :with_apple | Set the Apple-specific payload for the notification. |
| :with_google | Set the Google-specific payload for the notification. It can also be used to override APNs request headers, such as apns-push-type, apns-priority, etc. |
| :with_data | Set the data payload for the notification, sent to all platforms. |
| :silent | Create a silent notification that does not trigger a visual alert on the device. |
Action Push Native is licensed under MIT.