Skip to content

Commit c5046ab

Browse files
dadachiclaude
andcommitted
Wire deliver_by :action_push_native via Rails-native action_push_native
Install action_push_native 0.3.x and generate ApplicationPushNotification, ApplicationPushDevice, ApplicationPushNotificationJob, and config/push.yml. Add deliver_by :action_push_native to ItemTagCalledNotifier so push notifications route through Rails 8.1's Action Push Native (single abstraction over APNs + FCM) instead of the Noticed gem's per-platform :ios / :fcm deliverers. APNs/FCM credentials remain placeholders in config/push.yml — provision via bin/rails credentials:edit before enabling delivery. Bridging the existing Device registration API to ApplicationPushDevice (so registered tokens actually flow into Action Push Native delivery) is a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent db188c7 commit c5046ab

10 files changed

Lines changed: 144 additions & 2 deletions

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
- Add push notifications scaffolding via `noticed` v2 (#58)
88
- New `Device` model + migration (UUID primary key, unique on `[platform, token]`, `last_active_at` for staleness scope)
99
- New `Api::V1::Shopkeeper::DevicesController` — POST `/devices` is idempotent upsert (rebinds token to current shopkeeper); DELETE `/devices/:id` unregisters
10-
- Add `ApplicationNotifier` base class + example `ItemTagCalledNotifier` (no provider config yet — APNs / FCM delivery + ItemTag AASM wiring land in PR #2 once credentials are provisioned)
10+
- Add `ApplicationNotifier` base class + example `ItemTagCalledNotifier` with `deliver_by :action_push_native` wiring (Apple + Google push via Rails-native `action_push_native` 0.3.x)
11+
- Generate `ApplicationPushNotification` / `ApplicationPushDevice` / `ApplicationPushNotificationJob` and `config/push.yml` (APNs/FCM credentials still placeholders — provision via `bin/rails credentials:edit` before enabling delivery; ItemTag AASM trigger lands in a follow-up)
12+
- Note: the existing `Device` registration API (`POST /api/v1/shopkeeper/devices`) writes to the custom `Device` model, not `ApplicationPushDevice` — bridging the two (so registered tokens flow into Action Push Native delivery) is a follow-up
1113
- `Shopkeeper has_many :devices, :notifications`; new locale entries under `notifiers.item_tag_called`
1214
- 21 new test runs (Device model + DevicesController + notifier); full suite still 0 failures
1315

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,5 @@ group :test do
102102
gem "selenium-webdriver", ">= 4.20.1"
103103
gem "webmock"
104104
end
105+
106+
gem "action_push_native", "~> 0.3.1"

Gemfile.lock

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ GEM
33
specs:
44
aasm (5.5.2)
55
concurrent-ruby (~> 1.0)
6+
action_push_native (0.3.1)
7+
activejob (>= 8.0)
8+
activerecord (>= 8.0)
9+
googleauth (~> 1.14)
10+
httpx (~> 1.6)
11+
jwt (>= 2)
12+
railties (>= 8.0)
613
action_text-trix (2.1.18)
714
railties
815
actioncable (8.1.3)
@@ -153,6 +160,12 @@ GEM
153160
erubi (1.13.1)
154161
et-orbi (1.4.0)
155162
tzinfo
163+
faraday (2.14.1)
164+
faraday-net_http (>= 2.0, < 3.5)
165+
json
166+
logger
167+
faraday-net_http (3.4.2)
168+
net-http (~> 0.5)
156169
ffi (1.17.4-aarch64-linux-gnu)
157170
ffi (1.17.4-arm-linux-gnu)
158171
ffi (1.17.4-arm64-darwin)
@@ -164,11 +177,26 @@ GEM
164177
raabro (~> 1.4)
165178
globalid (1.3.0)
166179
activesupport (>= 6.1)
180+
google-cloud-env (2.3.1)
181+
base64 (~> 0.2)
182+
faraday (>= 1.0, < 3.a)
183+
google-logging-utils (0.2.0)
184+
googleauth (1.16.2)
185+
faraday (>= 1.0, < 3.a)
186+
google-cloud-env (~> 2.2)
187+
google-logging-utils (~> 0.1)
188+
jwt (>= 1.4, < 4.0)
189+
multi_json (~> 1.11)
190+
os (>= 0.9, < 2.0)
191+
signet (>= 0.16, < 2.a)
167192
hashdiff (1.2.1)
193+
http-2 (1.1.3)
168194
httparty (0.24.2)
169195
csv
170196
mini_mime (>= 1.0.0)
171197
multi_xml (>= 0.5.2)
198+
httpx (1.7.6)
199+
http-2 (>= 1.1.3)
172200
i18n (1.14.8)
173201
concurrent-ruby (~> 1.0)
174202
image_processing (1.14.0)
@@ -188,6 +216,8 @@ GEM
188216
json (2.19.4)
189217
jsonapi-serializer (2.2.0)
190218
activesupport (>= 4.2)
219+
jwt (3.1.2)
220+
base64
191221
language_server-protocol (3.17.0.5)
192222
lint_roller (1.1.0)
193223
logger (1.7.0)
@@ -232,8 +262,11 @@ GEM
232262
stimulus-rails
233263
turbo-rails
234264
msgpack (1.8.0)
265+
multi_json (1.21.1)
235266
multi_xml (0.8.1)
236267
bigdecimal (>= 3.1, < 5)
268+
net-http (0.9.1)
269+
uri (>= 0.11.1)
237270
net-imap (0.6.4)
238271
date
239272
net-protocol
@@ -260,6 +293,7 @@ GEM
260293
noticed (2.9.3)
261294
rails (>= 6.1.0)
262295
orm_adapter (0.5.0)
296+
os (1.1.4)
263297
ostruct (0.6.3)
264298
overcommit (0.69.0)
265299
childprocess (>= 0.6.3, < 6)
@@ -395,6 +429,11 @@ GEM
395429
rexml (~> 3.2, >= 3.2.5)
396430
rubyzip (>= 1.2.2, < 4.0)
397431
websocket (~> 1.0)
432+
signet (0.21.0)
433+
addressable (~> 2.8)
434+
faraday (>= 0.17.5, < 3.a)
435+
jwt (>= 1.5, < 4.0)
436+
multi_json (~> 1.10)
398437
smart_properties (1.17.0)
399438
solid_cable (3.0.12)
400439
actioncable (>= 7.2)
@@ -471,6 +510,7 @@ PLATFORMS
471510

472511
DEPENDENCIES
473512
aasm
513+
action_push_native (~> 0.3.1)
474514
acts_as_tenant
475515
after_commit_everywhere (~> 1.6)
476516
bootsnap (>= 1.4.2)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class ApplicationPushNotificationJob < ActionPushNative::NotificationJob
2+
# Enable logging job arguments (default: false)
3+
# self.log_arguments = true
4+
5+
# Report job retries via the `Rails.error` reporter (default: false)
6+
# self.report_job_retries = true
7+
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class ApplicationPushDevice < ActionPushNative::Device
2+
# Customize TokenError handling (default: destroy!)
3+
# rescue_from (ActionPushNative::TokenError) { Rails.logger.error("Device #{id} token is invalid") }
4+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class ApplicationPushNotification < ActionPushNative::Notification
2+
# Set a custom job queue_name
3+
# queue_as :realtime
4+
5+
# Controls whether push notifications are enabled (default: !Rails.env.test?)
6+
# self.enabled = Rails.env.production?
7+
8+
# Define a custom callback to modify or abort the notification before it is sent
9+
# before_delivery do |notification|
10+
# throw :abort if Notification.find(notification.context[:notification_id]).expired?
11+
# end
12+
end

app/notifiers/item_tag_called_notifier.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
class ItemTagCalledNotifier < ApplicationNotifier
2+
deliver_by :action_push_native do |config|
3+
config.devices = -> { ApplicationPushDevice.where(owner: recipient) }
4+
config.format = -> {
5+
{
6+
title: title,
7+
body: body,
8+
data: {url: url}
9+
}
10+
}
11+
end
12+
213
notification_methods do
314
def title
415
I18n.t("notifiers.item_tag_called.title", number: record.name)

config/push.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
shared:
2+
# Use bin/rails credentials:edit to set the apns secrets (as action_push_native:apns:key_id|encryption_key)
3+
apple:
4+
# Token auth params
5+
# See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns
6+
key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :key_id) %>
7+
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :encryption_key)&.dump %>
8+
9+
team_id: your_apple_team_id
10+
# Your identifier found on https://developer.apple.com/account/resources/identifiers/list
11+
topic: your.bundle.identifier
12+
13+
# Set this to the number of threads used to process notifications (default: 5).
14+
# When the pool size is too small a ConnectionPoolTimeoutError will be raised.
15+
# connection_pool_size: 5
16+
17+
# Change the request timeout (default: 30).
18+
# request_timeout: 60
19+
20+
# Decide when to connect to APNs development server.
21+
# Please note that anything built directly from Xcode and loaded on your phone will have
22+
# the app generate DEVELOPMENT tokens, while everything else (TestFlight, Apple Store, ...)
23+
# will be considered as PRODUCTION environment.
24+
# connect_to_development_server: <%= Rails.env.development? %>
25+
26+
# Use bin/rails credentials:edit to set the fcm secrets (as action_push_native:fcm:encryption_key)
27+
google:
28+
# Your Firebase project service account credentials
29+
# See https://firebase.google.com/docs/cloud-messaging/auth-server
30+
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :encryption_key)&.dump %>
31+
32+
# Firebase project_id
33+
project_id: your_project_id
34+
35+
# Set this to the number of threads used to process notifications (default: 5).
36+
# When the pool size is too small a ConnectionPoolTimeoutError will be raised.
37+
# connection_pool_size: 5
38+
39+
# Change the request timeout (default: 15).
40+
# request_timeout: 30
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This migration comes from action_push_native (originally 20250610075650)
2+
class CreateActionPushNativeDevice < ActiveRecord::Migration[8.0]
3+
def change
4+
create_table :action_push_native_devices do |t|
5+
t.string :name
6+
t.string :platform, null: false
7+
t.string :token, null: false
8+
t.belongs_to :owner, polymorphic: true
9+
10+
t.timestamps
11+
end
12+
end
13+
end

db/schema.rb

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)