Push notifications

Ruby Native sends push notifications from your Rails app to iOS and Android devices. The gem provides the native_push_tag helper to register devices and a built-in endpoint to receive their tokens.

#Add the push signal

Add native_push_tag to your layout. The app prompts the user for notification permission the first time it sees this signal.

<%= native_push_tag if user_signed_in? %>
import { NativePush } from "@ruby-native/react"

{user && <NativePush />}
<script setup>
import { NativePush } from "@ruby-native/vue"
defineProps(["user"])
</script>

<template>
  <NativePush v-if="user" />
</template>

Only show it for signed-in users. You need an authenticated user to associate the device token with.

#Database setup

Install the Action Push Native gem to handle device tokens and sending notifications. Run its install generator to create the migration:

bundle add action_push_native
bin/rails g action_push_native:install
bin/rails action_push_native:install:migrations
bin/rails db:migrate

When the user grants permission, the app sends the device token to your server via the gem's built-in endpoint.

#Who the device belongs to

The gem's endpoint calls your controller's current_user and saves the token to its push_devices association, which the Action Push Native install adds to your user model. If your app resolves the signed-in user differently, point the gem at it in an initializer with a method name or a callable:

# config/initializers/ruby_native.rb
RubyNative.configure do |config|
  config.current_user_resolver = :current_person        # a controller method
  # or
  config.current_user_resolver = -> { Current.person }  # any callable
end

Whatever it returns needs that push_devices association.

#Configure credentials

Each platform needs its own credentials so the gem can deliver through APNs (iOS) or FCM (Android):

#Sending notifications

Once credentials are configured, the action_push_native gem provides a notification class. The same call delivers to both iOS and Android devices:

notification = ApplicationPushNotification
  .with_data(path: "/links/#{link.id}")
  .new(title: "New bookmark", body: "Someone shared a link with you.")

notification.deliver_later_to(user.push_devices)

#Deep linking

with_data accepts two keys that control where the user lands when they tap the notification:

  • path: an internal route (e.g. /links/42). The app appends it to your base URL and loads it in-app. Use this for screens that live inside your Rails app.
  • url: a full external URL (e.g. https://dashboard.stripe.com/payments/pi_abc).
    • http / https: opens inside the app's embedded browser on iOS, or the device browser on Android.
    • Other schemes (mailto:, tel:, maps:, third-party app schemes): opens the relevant app if it's installed.

When both are present, url wins. Malformed URLs are dropped; the tap does not fall back to path.

#Badge counts

Pass badge: to set the app icon badge when the notification arrives:

notification = ApplicationPushNotification
  .with_data(path: "/links/#{link.id}")
  .new(
    title: "New bookmark",
    body: "Someone shared a link with you.",
    badge: user.unread_count
  )

On iOS the system sets the Home Screen badge to this number. Android has no numeric app icon badge; the count feeds the launcher dot and long-press preview instead.

The push badge does not update the tab bar badge. That comes from the badge signal, so include native_badge_tag on your pages and the two stay in sync the next time the user opens the app. See Badges for details.