The project is in a healthy, maintained state
Rails::Engine providing a thin wrapper around Typesense with idiomatic Rails integration.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 6.1
>= 5.0.0
 Project Readme

Search Engine for Typesense CI Gem Docs

Typesense Typesense Ruby gem

Warning

⚠️ This project is under maintenance – work in progress. APIs and docs may change. ⚠️

Mountless Rails::Engine for Typesense. Expressive Relation/DSL with JOINs, grouping, presets/curation — with strong DX and observability.

Note

This project is not affiliated with Typesense and is a wrapper for the typesense gem.

Versioning

The gem version mirrors the Typesense server major/minor it targets. Patch releases are reserved for gem-only fixes and enhancements.

Example: 30.1.x targets Typesense 30.1.

Quickstart

# Gemfile
gem "search-engine-for-typesense"
# config/initializers/search_engine_for_typesense.rb
SearchEngine.configure do |c|
  c.host = ENV.fetch("TYPESENSE_HOST", "localhost")
  c.port = 8108
  c.protocol = "http"
  c.api_key = ENV.fetch("TYPESENSE_API_KEY")
end
class SearchEngine::Product < SearchEngine::Base
  collection :products

  attribute :id, :integer
  attribute :name, :string

  query_by %i[name brand description]
end

SearchEngine::Product.where(name: "milk").select(:id, :name).limit(5).to_a

See Quickstart.

Host app SearchEngine models

By default, the gem manages a dedicated Zeitwerk loader for your SearchEngine models under app/search_engine/. The loader is initialized after Rails so that application models/constants are available, auto-reloads in development, and is eager-loaded in production/test.

Customize or disable via configuration:

# config/initializers/search_engine.rb
SearchEngine.configure do |c|
  # Relative to Rails.root or absolute; set to nil/false to disable
  c.search_engine_models = 'app/search_engine'
end

Usage examples

# Model
class SearchEngine::Product < SearchEngine::Base
  collection "products"

  attribute :id, :integer
  attribute :name, :string
end

# Basic query
SearchEngine::Product
  .where(name: "milk")
  # Explicit query_by always wins over model/global defaults
  .options(query_by: 'name,brand')
  .select(:id, :name)
  .order(price_cents: :asc)
  .limit(5)
  .to_a

# JOIN + nested selection
SearchEngine::Product
  .joins(:brands)
  .select(:id, :name, brands: %i[id name])
  .where(brands: { name: "Acme" })
  .per(10)
  .to_a

# Faceting + grouping
rel = SearchEngine::Product
        .facet_by(:brand_id, max_values: 5)
        .facet_by(:category)
        .group_by(:brand_id, limit: 3)
params = rel.to_h # compiled Typesense params

# Multi-search
result_set = SearchEngine.multi_search(common: { query_by: SearchEngine.config.default_query_by }) do |m|
  m.add :products, SearchEngine::Product.where("name:~rud").per(10)
  m.add :brands,   SearchEngine::Brand.all.per(5)
end
result_set[:products].found

# Upserting documents
product_record = Product.first
mapped = SearchEngine::Product.mapped_data_for(product_record)

# Map + upsert a single record
SearchEngine::Product.upsert(record: product_record)

# Upsert already-mapped data
SearchEngine::Product.upsert(data: mapped)

# Bulk upsert records (mapper runs internally)
SearchEngine::Product.upsert_bulk(records: Product.limit(2))

# Bulk upsert mapped payloads
SearchEngine::Product.upsert_bulk(data: [mapped])

Documentation

See the Docs

Test/offline mode

In test environments (Rails.env.test? or RACK_ENV=test), SearchEngine defaults to an offline client (SearchEngine::Test::OfflineClient) so no Typesense HTTP calls are made.

You can control this explicitly with:

  • SEARCH_ENGINE_TEST_MODE=1 to force offline mode
  • SEARCH_ENGINE_TEST_MODE=0 to disable offline mode
  • SEARCH_ENGINE_OFFLINE=1 (legacy alias)

If you set SearchEngine.configure { |c| c.client = ... }, the custom client is always used.

Example app

See examples/demo_shop — demonstrates single/multi search, JOINs, grouping, presets/curation, and DX/observability. Supports offline mode via the stub client (see Testing).

Contributing

See Docs Style Guide. Follow YARDoc for public APIs, add backlinks on docs landing pages, and redact secrets in examples.