High Leverage Rails
Introduction
Introduction to this course
Why use Ruby on Rails
Why use SQLite
Ruby on Rails + SQLite
Powering Your App with SQLite
Creating tables
Timestamps
Column types
Typeof
Ruby types
Creating table introduction
Creating table advanced
Inserting data
Updating data
Upserting data
Reading data
Virtual columns
Enums
Introduction to JSON
Indexing JSON
JSON table functions
Building a Modern Rails Application
Creating a new Rails application
Installing Solid Queue
Installing Solid Cache
Installing Solid Cable
Dockerfile
Application overview
Authentication
Base styles
Registration
Scaffolding posts
Polishing posts
Scaffolding comments
Polishing comments
Polishing models
Polishing controllers
Creating new post
Updating post
Reviewing MVP
Tagging posts
Custom tags
Friendly URLs
Full text search
Deploying & Operating Your App
Backups
Check Litestream locally
Verifying backups
Deployment options
Deploying with Hatchbox
Deployment constraints
Vertical scaling
Database access
Migrations
Locked video

Please purchase the course to watch this video.

Video thumbnail
Building a Modern Rails Application
Full text search

Full Course

$
129
$179
USD, one-time fee
This course came at the perfect time. I’ve recently gotten back into Rails after an 18-year hiatus, and this was a perfect refresher and shows just how much you can accomplish with Rails right out of the box.
Garrett Winder
Garrett Winder

Move fast and fix things

Application monitoring that helps developers get it done.

Rails hosting made simple

Deploy apps to servers that you own and control.

Summary

Learn how to add site-wide search to your Rails application using SQLite's Full-Text Search (FTS5) engine. We demonstrate how to create a virtual table, optimize queries with Common Table Expressions (CTEs), and build a fast, efficient search interface that ranks results by relevance. This method allows for high-performance, scalable full-text search without needing external search services.

Links

SQLite Full Text Search Documentation

Video Transcript

The last advanced feature we're adding to our Lorem News application is site-wide search, powered by SQLite's Full-Text Search (FTS) engine.

Now, let me ask you—would a "toy database" include a powerful and fully-featured full-text search engine out of the box? I don’t think so, but SQLite does, and it comes built-in. The official documentation is linked below, and I highly recommend checking it out. Even after working with SQLite for years, I was surprised at how much power, functionality, and flexibility is packed into its full-text search capabilities.

We’re going to build our site-wide search using SQLite’s native full-text search engine. Even so, we’re only scratching the surface, covering about 10-15% of what’s possible.

Setting Up Full-Text Search in Our Rails App

To start, we need to create a migration that sets up a virtual table for full-text search.

  1. We create an FTS5 (Full-Text Search version 5) virtual table called post_documents.
  2. We configure it to index both the title and body of our posts table.
  3. We optimize storage by using a contentless index, meaning we don’t duplicate data—we just store the searchable index.
  4. We use Unicode tokenization, removing diacritics (e.g., Ü becomes U) to ensure a more flexible and predictable search experience.

After running the migration, we now have our virtual table in place.

Building the Search Index and Query Methods

Next, we need to create a PostDocument Active Record model to handle search indexing and queries.

One key thing to note: Active Record models don’t have to be backed by a physical table—they can also be backed by virtual tables like our FTS5 index.

We define two class methods:

  • build_index! – Inserts or updates the full-text search index by pulling data from the posts table.
  • matches – Runs a search query, retrieving matching row IDs along with a relevance score.

Since our virtual table doesn’t store post content directly, we fetch the actual post records by joining results with our posts table.

Integrating Search into the Post Model

To allow our Post model to perform searches, we define a class-level search method.

Here’s how it works:

  1. We use a Common Table Expression (CTE) to define search matches as a virtual table.
  2. We join the matches with our posts table to fetch full post details.
  3. We sort results by relevance, ensuring the strongest matches appear first.

This efficiently ranks posts based on how well they match the search query.

Building the Search UI

Now that our backend is ready, we need to wire up the frontend.

  1. We add a search route that points to a search controller.
  2. We allow unauthenticated users to search all posts.
  3. We create a search form with a GET request, so searches update the URL query parameters.

Enhancing the Search UI

To improve user experience, we:

  • Display the current search term inside the input field.
  • Use flexbox styling to improve the layout.
  • Render search results dynamically, using the same partial as our posts index.
  • Show a "No posts found" message when there are no results.

With just a few refinements, the search UI now looks clean and functions smoothly.

Testing Our Search Implementation

Let’s do a quick test:

  1. Searching for "query" returns no results (as expected).
  2. Searching for "content" finds one post.
  3. Searching for "post" finds two posts (since it appears in multiple titles).

Everything is working exactly as intended!

Final Thoughts

  • We successfully implemented site-wide search using SQLite’s FTS5.
  • The search is optimized for performance, storage efficiency, and flexibility.
  • Our search ranks results based on relevance, ensuring users get the best matches first.

This completes the search feature in our Lorem News application! 🚀