mirror of
https://github.com/we-promise/sure.git
synced 2026-09-05 23:01:26 +00:00
* perf: memoize Family#balance_sheet/investment_statement, cache transactions-index side queries The account sidebar renders on every page (mobile + desktop, 3 tabs each) and calls Family#balance_sheet multiple times per render; neither it nor Family#investment_statement/InvestmentStatement#current_holdings were memoized, so each call rebuilt the underlying query from scratch. Memoize both per-user (family sharing means different users must not share a cached BalanceSheet/InvestmentStatement). Also cache TransactionsController#index's uncategorized_count and projected_recurring lookups, which run unconditionally on every request regardless of whether the underlying data changed, using the same entries_cache_version-keyed pattern already used elsewhere in the codebase (e.g. Transaction::Search#totals). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: address PR #3058 review feedback on cache invalidation and query reuse - Invalidate transactions-index caches when the current user's AccountShare access changes, not just on entries/recurring updates (CodeRabbit/Codex flagged revoked users could see stale data for up to a day). - Use full-precision timestamps instead of to_i in the cache keys so same-second updates aren't missed. - Reuse the already-memoized investment_account_ids in InvestmentStatement#current_holdings instead of an extra any? query. - Assert the rendered response instead of a controller instance variable in the uncategorized_count test, per CodeRabbit nitpick. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: assert rendered response, not implementation details, in PR #3058 tests Two CodeRabbit nitpicks from the second review round: the uncategorized-count cache-reuse assertion matched a scope name that never appears in generated SQL (making it vacuous), and the recurring-cache revocation test read the controller's private @projected_recurring ivar instead of the rendered page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: bust transactions-index caches on entry/recurring deletion and account status change jjmata's PR review flagged two invalidation gaps: hard-deleting an uncategorized entry or recurring transaction left the previous max updated_at unchanged (cache never busted), and toggling an account's active status doesn't touch entries/AccountShare at all. Fold in counts (like account_share_version already did) and a new Family#accounts_status_version, and move the version helpers onto Family/Current per the "fat models, skinny controllers" nit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: include merchant version in projected_recurring cache key Editing or deleting a FamilyMerchant doesn't touch recurring_transactions, so the cached projected-recurring list (rendered with merchant name/logo, expires_in: 1.day) could show stale merchant data for up to a day. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(transactions): version projected-recurring cache by referenced merchants, not just FamilyMerchant recurring_transactions.merchant_id can point at a shared ProviderMerchant (recurring detection copies transaction.merchant_id), not just a family-owned FamilyMerchant. merchants_version only tracked Family#merchants (FamilyMerchant), so a ProviderMerchant update (e.g. ProviderMerchant::Enhancer setting name/logo) left the cached projected recurring list stale for up to a day. Replace Family#merchants_version with #recurring_transaction_merchants_version, scoped to the merchant records actually referenced by the family's recurring transactions (both FamilyMerchant and ProviderMerchant), and bump the cache key version. Also fix a flaky test assertion that matched all recurring_transactions-table queries instead of the actual projection query, since computing the cache key itself still runs small COUNT/MAX queries against that table on a cache hit. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Gerald <248542187+gfr-free@users.noreply.github.com>
47 lines
1.3 KiB
Ruby
47 lines
1.3 KiB
Ruby
class Current < ActiveSupport::CurrentAttributes
|
|
attribute :user_agent, :ip_address
|
|
|
|
attribute :session
|
|
attribute :latest_sync_by_syncable, :latest_completed_sync_by_syncable, :syncing_by_syncable
|
|
|
|
delegate :family, to: :user, allow_nil: true
|
|
|
|
def user
|
|
impersonated_user || session&.user
|
|
end
|
|
|
|
def impersonated_user
|
|
session&.active_impersonator_session&.impersonated
|
|
end
|
|
|
|
def true_user
|
|
session&.user
|
|
end
|
|
|
|
def accessible_accounts
|
|
return family&.accounts unless user
|
|
user.accessible_accounts
|
|
end
|
|
|
|
def finance_accounts
|
|
return family&.accounts unless user
|
|
user.finance_accounts
|
|
end
|
|
|
|
def accessible_entries
|
|
return family&.entries unless user
|
|
family.entries.joins(:account).merge(Account.accessible_by(user))
|
|
end
|
|
|
|
# Used for invalidating caches whose results depend on the current user's
|
|
# account-share access (e.g. the transactions index's uncategorized count
|
|
# and projected recurring list, which are scoped to accessible accounts).
|
|
# Changes whenever an AccountShare granting/revoking the user's access is
|
|
# created, updated, or destroyed.
|
|
def account_share_version
|
|
return "0-" unless user
|
|
shares = AccountShare.where(user: user)
|
|
"#{shares.count}-#{shares.maximum(:updated_at)&.to_f}"
|
|
end
|
|
end
|