Link devices to sessions for automatic cleanup on logout
When a session is destroyed (user logs out), all devices registered to that session are automatically destroyed, preventing push notifications from being sent to logged-out devices. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
class AddSessionToActionPushNativeDevices < ActiveRecord::Migration[8.2]
|
||||
def change
|
||||
add_reference :action_push_native_devices, :session, foreign_key: true, type: :uuid
|
||||
end
|
||||
end
|
||||
Generated
+4
@@ -75,10 +75,12 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_18_120000) do
|
||||
t.uuid "owner_id"
|
||||
t.string "owner_type"
|
||||
t.string "platform", null: false
|
||||
t.uuid "session_id"
|
||||
t.string "token", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["owner_type", "owner_id", "token"], name: "idx_on_owner_type_owner_id_token_95a4008c64", unique: true
|
||||
t.index ["owner_type", "owner_id"], name: "index_action_push_native_devices_on_owner"
|
||||
t.index ["session_id"], name: "index_action_push_native_devices_on_session_id"
|
||||
end
|
||||
|
||||
create_table "action_text_rich_texts", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
@@ -852,4 +854,6 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_18_120000) do
|
||||
t.index ["account_id"], name: "index_webhooks_on_account_id"
|
||||
t.index ["board_id", "subscribed_actions"], name: "index_webhooks_on_board_id_and_subscribed_actions", length: { subscribed_actions: 255 }
|
||||
end
|
||||
|
||||
add_foreign_key "action_push_native_devices", "sessions"
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ class DevicesController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
ApplicationPushDevice.register(owner: Current.identity, **device_params)
|
||||
ApplicationPushDevice.register(session: Current.session, **device_params)
|
||||
head :created
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
class ApplicationPushDevice < ActionPushNative::Device
|
||||
def self.register(owner:, token:, platform:, name: nil)
|
||||
owner.devices.find_or_initialize_by(token: token).tap do |device|
|
||||
device.update!(platform: platform.downcase, name: name)
|
||||
belongs_to :session, optional: true
|
||||
|
||||
def self.register(session:, token:, platform:, name: nil)
|
||||
session.identity.devices.find_or_initialize_by(token: token).tap do |device|
|
||||
device.update!(session: session, platform: platform.downcase, name: name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
module Session::Devices
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_many :devices, class_name: "ApplicationPushDevice", dependent: :destroy
|
||||
end
|
||||
end
|
||||
@@ -155,6 +155,7 @@ module Fizzy
|
||||
::Account.include Account::Billing, Account::Limited
|
||||
::User.include User::NotifiesAccountOfEmailChange
|
||||
::Identity.include Authorization::Identity, Identity::Devices
|
||||
::Session.include Session::Devices
|
||||
::Signup.prepend Signup
|
||||
ApplicationController.include Authorization::Controller
|
||||
CardsController.include(Card::LimitedCreation)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
require "test_helper"
|
||||
|
||||
class Session::DevicesTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@session = sessions(:david)
|
||||
@identity = @session.identity
|
||||
end
|
||||
|
||||
test "destroying session destroys associated devices" do
|
||||
device = ApplicationPushDevice.register(
|
||||
session: @session,
|
||||
token: "test_token",
|
||||
platform: "apple",
|
||||
name: "Test iPhone"
|
||||
)
|
||||
|
||||
assert_difference -> { ApplicationPushDevice.count }, -1 do
|
||||
@session.destroy
|
||||
end
|
||||
|
||||
assert_nil ApplicationPushDevice.find_by(id: device.id)
|
||||
end
|
||||
|
||||
test "destroying session does not destroy devices from other sessions" do
|
||||
other_session = sessions(:kevin)
|
||||
|
||||
device = ApplicationPushDevice.register(
|
||||
session: other_session,
|
||||
token: "other_token",
|
||||
platform: "apple",
|
||||
name: "Other iPhone"
|
||||
)
|
||||
|
||||
assert_no_difference -> { ApplicationPushDevice.count } do
|
||||
@session.destroy
|
||||
end
|
||||
|
||||
assert ApplicationPushDevice.exists?(device.id)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user