diff --git a/app/models/portal.rb b/app/models/portal.rb index 9d2da6965..dfd5347aa 100644 --- a/app/models/portal.rb +++ b/app/models/portal.rb @@ -50,6 +50,13 @@ class Portal < ApplicationRecord schema: PortalConfigSchema::CONFIG_PARAMS_SCHEMA, attribute_resolver: ->(record) { record.config } + # Portal name/slug are embedded as help_center into the cached inbox payload + # (api/v1/models/_inbox.json.jbuilder), so portal changes must bump the + # account's inbox cache key. Destroy is covered too: dependent: :nullify + # detaches inboxes via update_all and skips their callbacks. + after_update_commit -> { account.update_cache_key('inbox') } + after_destroy_commit -> { account.update_cache_key('inbox') } + scope :active, -> { where(archived: false) } # TODO: 'website_token' is an unused reserved key; remove with a migration that scrubs it from existing portals' config diff --git a/app/models/team_member.rb b/app/models/team_member.rb index f99af264b..4caf05344 100644 --- a/app/models/team_member.rb +++ b/app/models/team_member.rb @@ -18,6 +18,12 @@ class TeamMember < ApplicationRecord belongs_to :user belongs_to :team validates :user_id, uniqueness: { scope: :team_id } + + # is_member is embedded into the cached team payload (per current user) via + # api/v1/models/_team.json.jbuilder, so membership changes must bump the team + # cache key. team is safe-navigated because destroying a team cascades here + # via destroy_async, by which point the team row is already gone. + after_commit -> { team&.account&.update_cache_key('team') }, on: [:create, :destroy] end TeamMember.include_mod_with('Audit::TeamMember') diff --git a/spec/models/portal_spec.rb b/spec/models/portal_spec.rb index c71a458fd..ce58da652 100644 --- a/spec/models/portal_spec.rb +++ b/spec/models/portal_spec.rb @@ -150,4 +150,22 @@ RSpec.describe Portal do expect(portal.display_title).to eq('Help Center | Acme') end end + + describe 'inbox cache invalidation' do + # Portal name/slug are embedded as help_center into the cached inbox + # payload (api/v1/models/_inbox.json.jbuilder), so portal changes must bump + # the account's inbox cache key. + let(:account) { create(:account) } + let!(:portal) { create(:portal, account: account) } + + it 'bumps the inbox cache key after update' do + expect(account).to receive(:update_cache_key).with('inbox') + portal.update!(name: 'Renamed Portal') + end + + it 'bumps the inbox cache key after destroy' do + expect(account).to receive(:update_cache_key).with('inbox') + portal.destroy! + end + end end diff --git a/spec/models/team_member_spec.rb b/spec/models/team_member_spec.rb index f37f70425..a00b09aa8 100644 --- a/spec/models/team_member_spec.rb +++ b/spec/models/team_member_spec.rb @@ -5,4 +5,20 @@ RSpec.describe TeamMember do it { is_expected.to belong_to(:team) } it { is_expected.to belong_to(:user) } end + + describe 'team cache invalidation' do + let(:team) { create(:team) } + let(:user) { create(:user) } + + it 'bumps the team cache key after create' do + expect(team.account).to receive(:update_cache_key).with('team') + create(:team_member, team: team, user: user) + end + + it 'bumps the team cache key after destroy' do + team_member = create(:team_member, team: team, user: user) + expect(team.account).to receive(:update_cache_key).with('team') + team_member.destroy + end + end end