Sticky Settings

A cross-app concept (requested in #322): when a user makes certain choices, the choice is recorded against their profile implicitly — no settings screen, no save button. It is not shown on the profile page and is changed only by revisiting the original area of choice and choosing differently.

Mechanics

  • One jsonb column holds all sticky settings: users.settings (null: false, default: {}).
  • Each setting is exposed through store_accessor on User:

    store_accessor :settings, :review_mode
    
  • The controller that owns the choice resolves it: an explicit choice in params wins and is persisted (only when it actually changed — no writes on every request); otherwise the stored value applies; otherwise the feature’s default.
  • Always validate the stored value against the feature’s whitelist before using it — the column is user data.

Current sticky settings

Setting Default Set by Used by
review_mode read Tapping a mode tab (Read/Write/Listen/Speak) on the review card Decks::ReviewsController#show — the Study button goes straight into review in the sticky mode; the mode-chooser page was removed
document_voices {} (the first read-aloud plan for a language picks a random catalog voice and persists it here, #586) The voice picker on the document reader toolbar (PATCH /documents/:id/voice), or implicitly by ReadAloudPlanner Text-to-speech: Resources::API::AttachAudioService and the read-aloud/dictation planners prefer the stored voice for the language (User#document_voice_for); values validated against VoiceCatalog

Adding a new sticky setting

  1. Add the key to the store_accessor :settings list on User.
  2. Resolve it in the owning controller (explicit param → persist if changed; stored value → validate; fallback default).
  3. Document it in the table above.

No migration is needed for new keys — the jsonb column absorbs them.


This site uses Just the Docs, a documentation theme for Jekyll.