Skip to main content
Related: Models, Indexer, Deletion, Client

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 using after_create_commit/after_update_commit/after_destroy_commit by default (post-transaction). SearchEngine.config.indexer.dispatch does not affect these hooks. Use the background-job pattern below if you need async behavior.
With explicit options:

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).
  • 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_commit → upsert document (post-transaction)
    • after_update_commit → upsert document (post-transaction)
    • after_destroy_commit → delete document (post-transaction)
  • 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_by when present, otherwise fall back to record.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 hydrated SearchEngine::<Model> instance.
    • Uses the SearchEngine model’s identify_by to compute id; falls back to record.id when not defined.
    • Returns nil when the model mapping is unavailable or the document is missing.
  • record.sync_search_engine_record → map and upsert this ActiveRecord instance to the collection.
    • Returns 1 when upserted, 0 on error; failures are logged.

Performance & Async

The default after_*_commit callbacks execute synchronously but only after the database transaction commits.
  • Configuration Ignored: The SearchEngine.config.indexer.dispatch setting (:active_job etc.) 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.

Callback timing

By default, ActiveRecordSyncable uses after_create_commit / after_update_commit / after_destroy_commit callbacks, which fire after the database transaction commits. This is safer — it avoids syncing documents for records that may be rolled back. To restore the legacy in-transaction behavior (after_create / after_update / after_destroy):

Migration from Syncable

  • Replace:
with:
No other API changes are required; keep using 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’s id is usable).
  • Unknown collection behavior: the concern resolves the target via alias or logical name; override collection: when needed.

Reference