Category guides

Search in Rails: pg_search, Ransack, Searchkick and Meilisearch

Category guides · · Published 2026-10-24

A magnifying glass lying on a newspaper under a spotlight
A magnifying glass resting on a newspaper.

"Search" covers two different jobs. Filtering narrows records by known fields: status, date range, owner. Full-text search ranks documents by how well their text matches what someone typed. Rails gems usually do one or the other, and mixing them up leads to the wrong tool.

Release figures are from RubyGems.org, October 2026.

Filtering with Ransack

Ransack (6.0.0, October 2026) turns form parameters into Active Record queries. Parameter names encode the attribute and the predicate, such as title_cont, created_at_gteq or author_name_eq, and the search_form_for helper builds the form, with sortable column links as a bonus.

@q = Article.ransack(params[:q])
@articles = @q.result.includes(:author).order(published_at: :desc)

Because Ransack lets request parameters choose which columns are queried, version 4.0 made allow-listing mandatory: each model must declare ransackable_attributes and ransackable_associations. Old tutorials that skip this step will raise errors, and should: without the allow-list, users could filter on columns such as password digests or tokens.

Ransack is the successor to MetaSearch, by the same original author, which itself followed Searchlogic in the Rails 2 era. Both predecessors have been unmaintained for over a decade.

Use it for admin screens and filter forms. It is not a relevance-ranked text search: _cont becomes a LIKE query.

PostgreSQL full-text search with pg_search

If your application runs on PostgreSQL, you may not need a separate search server at all. PostgreSQL's full-text search parses text into tsvector values, handles stemming by language and ranks results. pg_search (2.4.0, September 2026) wraps it in Active Record scopes:

class Article < ApplicationRecord
  include PgSearch::Model
  pg_search_scope :search_text,
    against: { title: "A", body: "B" },
    using: { tsearch: { dictionary: "english", prefix: true } }
end

Article.search_text("background jobs")

Beyond tsearch, it supports trigram similarity through the pg_trgm extension, useful for typo tolerance on short fields, and "multisearch", which indexes several models into one table for a site-wide search box. For large tables, store a precomputed tsvector column with a GIN index rather than computing it on every query; the pg_search README explains how.

Use it when you are on PostgreSQL, your data fits comfortably in the database, and good-enough relevance beats running another service. It does not support MySQL or SQLite.

A dedicated search engine

When you need typo tolerance across all fields, faceting, synonyms, fine-grained relevance tuning or search over very large datasets, a separate engine is the usual answer. The Rails integrations keep the index in sync with your models through callbacks or background jobs.

Hosted services such as Algolia also offer Rails gems. Whatever you choose, a search engine is another piece of infrastructure to run, monitor and back up, and an index that can drift from the database. Re-indexing must be easy and tested.

SQLite and MySQL

SQLite has its own full-text extension, FTS5, which you can use through a virtual table and raw SQL; with SQLite now a supported production option in Rails 8, this is worth knowing for small applications. MySQL offers FULLTEXT indexes and MATCH ... AGAINST queries. Neither has a Rails gem as established as pg_search, so expect to write some SQL.

Old search plugins

Rails 2 and 3 applications used acts_as_solr and its forks for Apache Solr, Ferret (a Ruby port of Lucene), acts_as_ferret, Searchlogic and MetaSearch. All are long unmaintained. Solr itself is very much alive; the Sunspot gems were the later Rails integration for it, so check their current release status before relying on them.

Choosing

NeedReasonable choice
Filter forms, admin screensRansack, or hand-written scopes
Full-text search on PostgreSQLpg_search with a GIN index
Typo tolerance, facets, large dataSearchkick or meilisearch-rails
Existing Sphinx or Manticore setupThinking Sphinx

Search results usually need paging too; see Pagination in Rails, and let the search engine paginate rather than loading all hits into Ruby.

Location is a separate filter from text: "flats within two kilometres of this station" needs coordinates and a distance query rather than a search index. The guide to building a property search with geocoding gems covers that side and combines a radius scope with ordinary filters on price.