ActiveRecordSyncable (ActiveRecord Concern)
Keep a Typesense collection in sync with your ActiveRecord model. When enabled, the concern upserts on create/update and deletes on destroy so your Typesense documents mirror your database rows.Note: Formerly named
SearchEngine::Syncable. It has been renamed to SearchEngine::ActiveRecordSyncable.Quick start
Callbacks run synchronously (
after_create/after_update/after_destroy by default); SearchEngine.config.indexer.dispatch does not affect these hooks. Use the background-job pattern below if you need async behavior.Defaults and validation
- collection: inferred from model name (
tableize, e.g.,Product→ “books”).- Upserts require a
SearchEngine::<Model>mapping for that logical collection. - If the mapping is missing at boot, a warning is logged and the concern will attempt lazy resolution later. When still unavailable at upsert time, it logs and skips upsert (no exception).
- Upserts require a
- on: defaults to
[:create, :update, :destroy].- Accepts a single symbol/string or an array; values are normalized case‑insensitively.
What the concern does
- Registers callbacks on your AR model (installed once per class reload):
after_create→ upsert documentafter_update→ upsert documentafter_destroy→ delete document
- Upserts call your SearchEngine model:
SearchEngine::<Model>.upsert(record: …)using your mapping (see Indexer and Models). - Deletes compute the document id using the SearchEngine model’s
identify_bywhen present, otherwise fall back torecord.id. - Target collection resolution prefers alias → physical mapping when available (see Schema).
Lazy resolution & error handling
- Mapping resolution is best‑effort at boot; if unavailable, a one‑time warning is logged. The concern resolves the SearchEngine model lazily on first use.
- Upsert/delete errors are logged and swallowed to avoid interrupting AR lifecycle callbacks (see logs under
search_engine_syncable).
Instance helpers
record.search_engine_record→ fetch the associated Typesense document as a hydratedSearchEngine::<Model>instance.- Uses the SearchEngine model’s
identify_byto compute id; falls back torecord.idwhen not defined. - Returns
nilwhen the model mapping is unavailable or the document is missing.
- Uses the SearchEngine model’s
record.sync_search_engine_record→ map and upsert this ActiveRecord instance to the collection.- Returns
1when upserted,0on error; failures are logged.
- Returns
Performance & Async
The defaultafter_create/update/destroy callbacks execute synchronously (inline) within the request cycle (and often within the DB transaction).
- Configuration Ignored: The
SearchEngine.config.indexer.dispatchsetting (:active_jobetc.) does not apply here. That setting controls bulk rebuilds only. - For High Throughput: If you need background processing to avoid blocking user requests, disable the concern’s auto-sync and manually enqueue a job.
Callbacks timing: after_* vs after_commit
- Uses
after_create/after_update/after_destroyby default for immediacy. - If your app requires Typesense writes only after DB commit, switch to
after_commitequivalents in your app; the upsert/delete calls are safe to use there as well.
Migration from Syncable
- Replace:
search_engine_syncable.
Troubleshooting
- “Upsert skipped: no SearchEngine model”: create a SearchEngine model and mapping for the collection; see Models and Indexer.
- “Cannot delete without id”: ensure your SearchEngine model defines
identify_by(or that the AR record’sidis usable). - Unknown collection behavior: the concern resolves the target via alias or logical name; override
collection:when needed.