]
```
--------------------------------
### Install Unaccent Extension
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
SQL command to install the 'unaccent' extension if it is not already present. This extension is required for accent normalization.
```sql
CREATE EXTENSION IF NOT EXISTS unaccent;
```
--------------------------------
### Basic Highlighting Configuration
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Configure basic highlighting for search results using custom start and stop selectors.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :search,
against: :content,
using:
{
tsearch: {
highlight: {
StartSel: '',
StopSel: ''
}
}
}
end
# Usage in view
<% Article.search("ruby").with_pg_search_highlight.each do |article| %>
<%= article.title %>
<%= raw(article.pg_search_highlight) %>
<% end %>
```
--------------------------------
### Consistent Multisearchable Setup Pattern
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Illustrates a pattern for consistently setting up `multisearchable` across different models and includes a Rake task for rebuilding all multisearchable models.
```ruby
# Pattern: Consistent multisearchable setup
class Article < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :body]
end
class Product < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:name, :description]
end
class Comment < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:text]
end
# Rake task to rebuild all multisearchable models
namespace :pg_search do
task rebuild_all: :environment do
[Article, Product, Comment].each do |model|
PgSearch::Multisearch.rebuild(model)
end
end
end
```
--------------------------------
### RankingExpression Syntax Examples
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/11_types.md
Illustrates various ways to construct SQL ranking expressions using predefined features, custom database columns, and arithmetic operators.
```ruby
":tsearch"
```
```ruby
":tsearch * 2"
```
```ruby
":tsearch + :trigram"
```
```ruby
"( :tsearch * 2) + :trigram"
```
```ruby
"(articles.views) + (:tsearch / 2.0)"
```
--------------------------------
### Install pg_search Gem
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Install the pg_search gem using the RubyGems package manager.
```bash
$ gem install pg_search
```
--------------------------------
### Using Valid Options
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Ensure all provided options for pg_search_scope are valid. This example shows a mix of invalid and valid options, followed by a correct configuration.
```ruby
# ❌ Invalid options
pg_search_scope :search,
against: :title,
unknown: true,
also_invalid: false
```
```ruby
# ✅ Valid options
pg_search_scope :search,
against: :title,
using: :tsearch,
ranked_by: ":tsearch",
ignoring: :accents
```
--------------------------------
### Configure and Use .with_pg_search_highlight
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/03_pg_search_model.md
Shows how to configure the `highlight` option within `pg_search_scope` using custom start and stop selectors, and then uses `.with_pg_search_highlight` to retrieve results with highlighted terms.
```ruby
Article.pg_search_scope :search,
against: :content,
using: {
tsearch: {
highlight: {
StartSel: '',
StopSel: ''
}
}
}
results = Article.search("database").with_pg_search_highlight
puts results.first.pg_search_highlight # => "...the database..."
```
--------------------------------
### Complete Type Declaration Example
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/11_types.md
Demonstrates the usage of various PgSearch types including SearchScopeOptions, TSearchOptions, HighlightOptions, and RankingExpression within a configuration hash.
```ruby
# Types used in this example:
# SearchScopeOptions, TSearchOptions, HighlightOptions, RankingExpression
article_options = {
# Type: SearchScopeOptions
against: {
# Type: Hash
title: 'A',
body: 'B'
},
using: {
# Type: Hash
tsearch: {
# Type: TSearchOptions
dictionary: 'english',
prefix: true,
highlight: {
# Type: HighlightOptions
StartSel: '',
StopSel: '',
MaxWords: 50
}
},
trigram: {
threshold: 0.3
}
},
ranked_by: "(:tsearch * 2) + :trigram", # Type: RankingExpression
query: "ruby"
}
```
--------------------------------
### Configure Multiple Search Techniques with Options
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Pass multiple :using options with additional configurations for each search technique. For example, enable prefix search for :tsearch.
```ruby
class Beer < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :search_name,
against: :name,
using: {
:trigram => {},
:dmetaphone => {},
:tsearch => { :prefix => true }
}
end
```
--------------------------------
### Global Search (Multi-Model) Setup and Usage
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md
Set up models for global search using `multisearchable` and perform searches using `PgSearch.multisearch`. You can filter results by type or include associated data.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :body]
end
```
```ruby
PgSearch.multisearch("query")
```
```ruby
PgSearch.multisearch("query").where(searchable_type: "Article")
```
```ruby
PgSearch.multisearch("query").includes(:searchable)
```
--------------------------------
### TSearch Normalization Example
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Illustrates how normalizer is applied to column expressions and query terms in TSearch before and after normalization, including accent removal and disallowed character replacement.
```ruby
# Before normalization:
to_tsvector('simple', articles.title) @@ to_tsquery('simple', 'query')
# After normalization (ignoring: :accents):
to_tsvector('simple', regexp_replace(unaccent(articles.title), '[...]', '', 'g')) @@
to_tsquery('simple', regexp_replace(unaccent('query'), '[...]', '', 'g'))
```
--------------------------------
### Example Usage of .with_pg_search_rank
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/03_pg_search_model.md
Demonstrates chaining `.with_pg_search_rank` with other ActiveRecord scopes like `.limit` and `.includes`, then accessing the `pg_search_rank` attribute within the results.
```ruby
results = Article.search("ruby")
.with_pg_search_rank
.limit(10)
.includes(:author)
results.each do |article|
puts "#{article.title}: #{article.pg_search_rank}"
end
```
--------------------------------
### PgSearch Scope Configuration Example
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/07_features.md
Demonstrates how to configure a PgSearch scope using different features with specific options. The `only` option limits columns for a feature, while `sort_only` indicates the feature is used solely for ranking.
```ruby
pg_search_scope :search,
against: [:title, :body, :tags],
using:
tsearch: { only: [:title, :body] }, # Only these columns
trigram: { sort_only: true } # Only for ranking
```
--------------------------------
### Basic Multi-Model Search Setup
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Set up multiple ActiveRecord models for global search. Include the `PgSearch::Model` module and define the fields to be searched using `multisearchable`. A global search function is provided to query across all indexed models.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :body]
end
class Product < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:name, :description]
end
class Comment < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:text]
end
def global_search(query)
PgSearch.multisearch(query).includes(:searchable).limit(20)
end
```
--------------------------------
### Custom PgSearch Document Table Schema with Additional Columns
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/04_document.md
Shows an example of a custom migration for the pg_search_documents table, demonstrating how to add additional columns like foreign keys to associate with other models.
```ruby
create_table :pg_search_documents do |t|
t.text :content
t.references :author, index: true # Custom attribute
t.belongs_to :searchable, polymorphic: true, index: true
t.timestamps null: false
end
```
--------------------------------
### Trigram Normalization Example
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Shows the application of normalization to both query and document columns for Trigram search, including accent removal and disallowed character replacement.
```ruby
# Before:
articles.title % 'query'
# After (ignoring: :accents):
regexp_replace(unaccent(articles.title), '[...]', '', 'g') %
regexp_replace(unaccent('query'), '[...]', '', 'g')
```
--------------------------------
### Testing Normalization in Rails Console
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Provides examples for testing normalization behavior using the Rails console. It shows how to define a search scope with and without normalization and verifies the generated SQL and search results.
```ruby
# With normalization
Article.pg_search_scope :search, against: :title, ignoring: :accents
results = Article.search("cafe")
```
```ruby
# Check the generated SQL
Article.search("cafe").to_sql
# => SELECT ... WHERE regexp_replace(unaccent(...), ...)
```
```ruby
# Create test records
Article.create!(title: "Café au Lait")
Article.search("cafe").first.title # => "Café au Lait"
```
```ruby
# Without normalization
Article.pg_search_scope :strict, against: :title
Article.strict("cafe") # => [] (exact match required)
Article.strict("café") # => [article]
```
--------------------------------
### Configure Accent Normalization
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Example of how to configure accent normalization within a pg_search_scope. This setting makes searches insensitive to accent marks.
```ruby
pg_search_scope :search,
against: :title,
ignoring: :accents
```
--------------------------------
### Get Searchable Text for an Instance
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/08_multisearchable.md
Concatenates text from all `:against` columns, joined by spaces. Calls each column name as a method on the instance and converts results to strings.
```ruby
article = Article.create!(title: "Rails Tips", body: "This is content...")
article.searchable_text # => "Rails Tips This is content..."
```
--------------------------------
### RSpec Search Specification Example
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Write RSpec tests to verify your `pg_search` scopes. Use `before` blocks to set up test data and `describe` blocks to test specific search functionalities, including ranking.
```ruby
RSpec.describe "Article Search" do
before do
Article.create!(title: "Ruby Basics", body: "Learn ruby fundamentals...")
Article.create!(title: "Rails Guide", body: "Web framework...")
Article.create!(title: "Python Tips", body: "Python best practices...")
end
describe "full_search" do
it "finds articles by title" do
results = Article.full_search("Ruby")
expect(results.count).to eq(1)
expect(results.first.title).to eq("Ruby Basics")
end
it "finds articles by body" do
results = Article.full_search("fundamentals")
expect(results.count).to eq(1)
end
it "returns ranked results" do
results = Article.full_search("ruby").with_pg_search_rank
expect(results.first.pg_search_rank).to be_positive
end
end
describe "multisearch" do
before { Article.create!(title: "Test", body: "Content") }
it "finds articles in global search" do
results = PgSearch.multisearch("Test")
expect(results).to have(1).item
expect(results.first.searchable).to be_a(Article)
end
end
end
```
--------------------------------
### Model-Specific Search Setup and Usage
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md
Define model-specific search scopes using `pg_search_scope` for targeted searches within a single model. Results can be limited or include ranking information.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :search, against: [:title, :body]
end
```
```ruby
Article.search("query")
```
```ruby
Article.search("query").limit(10)
```
```ruby
Article.search("query").with_pg_search_rank
```
--------------------------------
### ScopeOptions Initialization and Apply
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/09_scope_options.md
Demonstrates how to initialize ScopeOptions and apply it to an ActiveRecord scope to generate a search query.
```APIDOC
## ScopeOptions#apply(scope)
### Description
Applies the search configuration to an ActiveRecord scope, adding joins, ordering, and selecting.
### Method
`apply`
### Parameters
#### Path Parameters
- **scope** (Relation) - Required - Starting ActiveRecord relation (e.g., `Model.all`)
### Returns
`ActiveRecord::Relation` with search applied
### Example
```ruby
config = PgSearch::Configuration.new(options, model)
scope_options = PgSearch::ScopeOptions.new(config)
result_scope = scope_options.apply(starting_scope)
```
```
--------------------------------
### Get Highlighted HTML with .with_pg_search_highlight
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/11_types.md
Use the .with_pg_search_highlight scope to get an HTML string with search terms highlighted. The highlighting is generated by PostgreSQL's ts_headline function and is not escaped.
```ruby
result = Article.search("ruby").with_pg_search_highlight.first
result.pg_search_highlight # => "Learn ruby programming..."
```
--------------------------------
### Generate and Run pg_search Migration for Multi-search
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Generate the migration file for the pg_search_documents table and then run the database migration.
```bash
$ rails g pg_search:migration:multisearch
$ rake db:migrate
```
--------------------------------
### TSearch with Ranking Normalization
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/07_features.md
Apply ranking normalization algorithms to adjust search result scores, for example, by document length.
```ruby
# Normalize by document length (divide rank by length)
pg_search_scope :search,
against: :content,
using: { tsearch: { normalization: 2 } }
```
--------------------------------
### Example Custom Unaccent SQL Function
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Defines a custom PostgreSQL function for unaccenting text. Ensure it is IMMUTABLE for indexability.
```sql
CREATE OR REPLACE FUNCTION my_custom_unaccent(text)
RETURNS text AS $$
BEGIN
RETURN unaccent($1);
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
-- Can be indexed
CREATE INDEX idx_title_unaccent ON articles
USING gin(to_tsvector('english', my_custom_unaccent(title)));
```
--------------------------------
### Initialize Normalizer
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Instantiate the Normalizer with a configuration object. This object dictates the normalization rules to be applied.
```ruby
normalizer = PgSearch::Normalizer.new(config)
```
--------------------------------
### Initialize PgSearch Configuration
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/06_configuration.md
Instantiate the Configuration class with search options and the target model class. This sets up the parameters for a pg_search scope.
```ruby
config = PgSearch::Configuration.new(
{
against: [:title, :body],
using: [:tsearch, :trigram],
query: "search term"
},
Article # model class
)
```
--------------------------------
### Invalid Configuration: Unknown Option
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/06_configuration.md
Shows an invalid configuration attempt with an unrecognized option key.
```ruby
Configuration.new({against: :title, unknown_key: true}, Article)
# => ArgumentError: unknown keys: :unknown_key
```
--------------------------------
### Instantiate and Rebuild with Rebuilder Class
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/05_multisearch.md
Use the low-level `PgSearch::Multisearch::Rebuilder` class to manually control the rebuild process. This class automatically detects the most efficient rebuild strategy.
```ruby
rebuilder = PgSearch::Multisearch::Rebuilder.new(Article)
rebuilder.rebuild
```
--------------------------------
### Handle PG::UndefinedFunction for Trigram Extension
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Occurs when using the `:trigram` feature without the `pg_trgm` PostgreSQL extension. Install it using the provided SQL command.
```ruby
pg_search_scope :search, against: :title, using: :trigram
Article.search("test")
# => PG::UndefinedFunction: ERROR: operator does not exist: text % text
```
```sql
CREATE EXTENSION IF NOT EXISTS pg_trgm;
```
--------------------------------
### Handle PG::UndefinedFunction for Unaccent Extension
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Triggered when using `:ignoring: :accents` without the `unaccent` PostgreSQL extension. Install it using the provided SQL command.
```ruby
pg_search_scope :search, against: :title, ignoring: :accents
Article.search("cafe")
# => PG::UndefinedFunction: ERROR: function unaccent(unknown) does not exist
```
```sql
CREATE EXTENSION IF NOT EXISTS unaccent;
```
--------------------------------
### Invalid Configuration: Missing Required Option
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/06_configuration.md
Demonstrates an invalid configuration due to a missing required :against option.
```ruby
Configuration.new({query: "test"}, Article)
# => ArgumentError: the search scope must have :against, :associated_against, or :tsvector_column in its options
```
--------------------------------
### Configure Global Multisearch Options
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/02_pg_search_module.md
Set global configuration options for all multisearch queries. This can be done in an initializer file. Supports hash or proc for dynamic configuration.
```ruby
# config/initializers/pg_search.rb
PgSearch.multisearch_options = {
using: [:tsearch, :trigram],
ignoring: :accents
}
# Or as a Proc for dynamic configuration
PgSearch.multisearch_options = lambda { |query|
{ using: query.length > 3 ? [:tsearch, :trigram] : :trigram }
}
```
--------------------------------
### Implement Valid Search Scopes
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Shows how to correctly define search scopes using valid features, including single features, multiple features, and features with options.
```ruby
# ✅ Use only valid features
pg_search_scope :search,
against: :title,
using: :tsearch
# ✅ Multiple valid features
pg_search_scope :search,
against: :title,
using: [:tsearch, :trigram]
# ✅ With feature-specific options
pg_search_scope :search,
against: :title,
using: {
tsearch: {},
trigram: {}
}
```
--------------------------------
### Get Attributes for Search Document
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/08_multisearchable.md
Returns a hash of attributes to be saved to the search document. Always includes `:content` with searchable text and can include additional attributes if configured.
```ruby
article = Article.create!(title: "Rails", body: "Content")
attrs = article.pg_search_document_attrs
# => {content: "Rails Content"}
```
--------------------------------
### Initialize ScopeOptions
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/09_scope_options.md
Instantiate ScopeOptions by first creating a Configuration object and then passing it to the ScopeOptions constructor. The apply method is then used to modify an existing ActiveRecord scope.
```ruby
config = PgSearch::Configuration.new(options, model)
scope_options = PgSearch::ScopeOptions.new(config)
result_scope = scope_options.apply(starting_scope)
```
--------------------------------
### Ignore Accent Marks in Searches
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Set `ignoring: :accents` in `pg_search_scope` to ignore accent marks in both the searchable text and query terms. This requires the PostgreSQL `unaccent` extension to be installed.
```ruby
class SpanishQuestion < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :gringo_search,
against: :word,
ignoring: :accents
end
what = SpanishQuestion.create(word: "Qué")
how_many = SpanishQuestion.create(word: "Cuánto")
how = SpanishQuestion.create(word: "Cómo")
SpanishQuestion.gringo_search("Que") # => [what]
SpanishQuestion.gringo_search("Cüåñtô") # => [how_many]
```
--------------------------------
### Tiebreaker for Consistent Ordering
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Implement a tiebreaker in the pg_search_scope to ensure consistent ordering of search results, especially for pagination. This example uses 'updated_at' and 'id' to guarantee stable results.
```ruby
class Product < ActiveRecord::Base
include PgSearch::Model
# Ensure consistent pagination
pg_search_scope :search,
against: [:name, :description],
order_within_rank: "products.updated_at DESC, products.id ASC"
end
# Guarantees page consistency across requests
(1..100).each do |page|
results = Product.search("widget").page(page).per(10)
# Results are consistent each time
end
```
--------------------------------
### PgSearch Document Creation Flow
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/08_multisearchable.md
This flow outlines the steps involved when an instance is created, saved, and its corresponding PgSearch document is generated and made searchable.
```ruby
article = Article.create!(title: "Test", body: "Content...")
# 1. Article instance created
# 2. Article saved to database
# 3. after_save callback fires
# 4. update_pg_search_document called
# 5. :if/:unless conditions checked → pass
# 6. pg_search_document_attrs computed → {content: "Test Content..."}
# 7. PgSearch::Document.create! called
# 8. Document is now searchable via PgSearch.multisearch
```
--------------------------------
### SQL Complexity Comparison
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Illustrates the difference in SQL query complexity between searches without normalization and those with accent normalization. Normalization adds complexity, potentially impacting performance.
```sql
-- Without normalization (fast)
WHERE title LIKE 'test%'
```
```sql
-- With accent normalization (slower)
WHERE regexp_replace(unaccent(title), '[...]', '', 'g') LIKE 'test%'
```
--------------------------------
### Chaining Normalizers with DMetaphone
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md
Demonstrates how to wrap a base normalizer with DMetaphone for combined transformations. Apply multiple transformations by adding normalizations to the chained normalizer.
```ruby
base_normalizer = Normalizer.new(config)
# DMetaphone wraps the base:
dmetaphone_normalizer = DMetaphone::Normalizer.new(base_normalizer)
# Apply both transformations:
dmetaphone_normalizer.add_normalization("column")
# => pg_search_dmetaphone(regexp_replace(unaccent(column), ...))
```
--------------------------------
### Custom Ranking Expression with Boost
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Define a custom ranking expression for a search scope to boost recent articles. This example uses the tsearch method and a formula that prioritizes newer content.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
# Rank by relevance, but boost recent articles
pg_search_scope :trending_search,
against: [:title, :body],
ranked_by: "(:tsearch / (1 + (EXTRACT(EPOCH FROM (now() - articles.created_at)) / 86400))) ASC",
using: :tsearch
end
```
--------------------------------
### Article Creation with after_save Callback
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/08_multisearchable.md
Demonstrates the automatic creation of a pg_search_document when an Article is saved, provided multisearch is enabled and conditions are met.
```ruby
article = Article.create!(title: "New")
# Callback fires -> creates pg_search_document
```
--------------------------------
### ColumnObject Definition
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/11_types.md
Represents a searchable column within a model. It includes the column's name, an optional weight for relevance, and methods to get its full qualified name and SQL expression.
```ruby
class Column
attr_reader :name: String # Column name
attr_reader :weight: String | nil # 'A', 'B', 'C', 'D', or nil
def full_name: String # Qualified name with table
def to_sql: String # SQL expression for this column
end
```
--------------------------------
### Conditional Indexing: Publish/Unpublish Logic
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Control which records are indexed for search based on a condition. Use the `if` option with a method that returns true for records to be indexed. This example demonstrates indexing only published articles.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :body],
if: :published?
def published?
published_at.present? && published_at <= Time.now
end
scope :published, -> { where("published_at <= ?", Time.now) }
end
# Usage
article = Article.create!(title: "Test", published_at: 1.day.from_now)
PgSearch.multisearch("Test") # => [] (not published)
article.update!(published_at: Time.now)
PgSearch.multisearch("Test") # => [document] (now published)
```
--------------------------------
### Search Scope Configuration for Highlight
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Compares search scope configurations, showing one that won't work with highlight and another (`highlighted_search`) that is correctly configured for highlight functionality.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
# Without highlight configuration - won't work
pg_search_scope :basic_search, against: :content
# With highlight configuration - works
pg_search_scope :highlighted_search,
against: :content,
using: {
tsearch: {
highlight: {
StartSel: '',
StopSel: ''
}
}
}
end
# Use the right scope based on needs
def search_with_highlight(query)
Article.highlighted_search(query).with_pg_search_highlight
end
```
--------------------------------
### Perform Trigram Search for Typo Tolerance
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Use the `:trigram` option to find records based on matching three-letter substrings. This method offers tolerance for typos and misspellings. The `pg_trgm` extension must be installed.
```ruby
class Website < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :kinda_spelled_like,
against: :name,
using: :trigram
end
yahooo = Website.create! name: "Yahooo!"
yohoo = Website.create! name: "Yohoo!"
gogle = Website.create! name: "Gogle"
facebook = Website.create! name: "Facebook"
Website.kinda_spelled_like("Yahoo!") # => [yahooo, yohoo]
```
--------------------------------
### Combining Multiple Feature Rankings
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/09_scope_options.md
Demonstrates how rankings from multiple features are combined using addition in the ORDER BY clause. Supports custom ranking expressions and integration with database columns.
```sql
# Default (single tsearch feature):
ORDER BY ts_rank(...) DESC
```
```sql
# Multiple features:
ORDER BY (:tsearch + :trigram + :dmetaphone) DESC
```
```sql
# Custom ranked_by:
ranked_by: ":tsearch * 2 + :trigram"
ORDER BY (:tsearch * 2 + :trigram) DESC
```
```sql
# With database columns:
ranked_by: "(articles.created_at DESC) + (:tsearch / 2.0)"
ORDER BY ((articles.created_at DESC) + (:tsearch / 2.0)) DESC
```
--------------------------------
### Paginate Search Results
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Implement pagination for search results using the 'page' and 'per' methods, commonly used with libraries like Kaminari. Ensure to include the searchable association for eager loading.
```ruby
def search_with_pagination(query, page, per_page)
PgSearch.multisearch(query)
.includes(:searchable)
.page(page)
.per(per_page)
end
# Or with Kaminari
def search(query)
PgSearch.multisearch(query)
.includes(:searchable)
.page(params[:page])
.per(20)
end
```
--------------------------------
### Conditional Indexing: Draft Exclusion
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Exclude records from search indexing based on a condition. Use the `unless` option with a method that returns true for records to be excluded. This example prevents indexing of draft documents.
```ruby
class Document < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :content],
unless: :draft?
end
```
--------------------------------
### Efficient Rebuilding with Direct Attributes
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/05_multisearch.md
Use this strategy when all columns specified in `:against` are direct Active Record attributes. It leverages a single SQL INSERT...SELECT statement for maximum efficiency.
```ruby
class Article < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :body] # Direct attributes - uses single SQL
end
PgSearch::Multisearch.rebuild(Article) # Single INSERT...SELECT statement
```
--------------------------------
### Get Rank Score with .with_pg_search_rank
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/11_types.md
Use the .with_pg_search_rank scope to add a numeric rank attribute to search results. Higher scores indicate greater relevance. The rank is accessed via the .pg_search_rank method.
```ruby
results = Article.search("ruby").with_pg_search_rank
results.map(&:pg_search_rank) # => [0.456, 0.234, 0.123]
```
--------------------------------
### Generate and Migrate Search Tables
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md
Generate and migrate the necessary database tables for PgSearch. This includes migrations for multisearch and optionally for dmetaphone.
```bash
rails generate pg_search:migration:multisearch
rake db:migrate
```
```bash
rails generate pg_search:migration:dmetaphone
rake db:migrate
```
--------------------------------
### Get Relevance Rank with pg_search_rank
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/03_pg_search_model.md
Use this method on search results to retrieve the relevance score. Ensure `.with_pg_search_rank` was chained to the search scope. The score is a Float, higher values indicating greater relevance.
```ruby
results = Article.search("rails").with_pg_search_rank
results.first.pg_search_rank # => 0.0759909
```
--------------------------------
### Specify Search Features (`using`)
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/06_configuration.md
Select which search algorithms to employ, such as :tsearch or :trigram. Options can be provided per feature.
```ruby
using: :tsearch
```
```ruby
using: [:tsearch, :trigram]
```
```ruby
using: {
tsearch: { dictionary: 'english', prefix: true },
trigram: { threshold: 0.5 }
}
```
```ruby
using: [:tsearch, {trigram: {threshold: 0.3}}]
```
--------------------------------
### Rake Task to Rebuild Search Documents
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Use the provided Rake task to rebuild search documents for a given model. An optional second argument can specify the PostgreSQL schema search path for multi-tenant setups.
```bash
$ rake pg_search:multisearch:rebuild[BlogPost]
```
```bash
$ rake pg_search:multisearch:rebuild[BlogPost,my_schema]
```
--------------------------------
### PgSearch::Configuration Methods
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md
Provides methods for configuring search behavior and accessing configuration details.
```APIDOC
## PgSearch::Configuration
### Class Methods
#### `alias(*strings)`
**Description**: Creates a unique alias for the configuration.
**Parameters**:
- `*strings` (Array) - Strings to form the alias.
**Returns**: String - The generated unique alias.
### Instance Methods
- `.columns`: Returns an array of `Column` objects representing the columns configured for searching.
- `.regular_columns`: Returns an array of `Column` objects for regular columns.
- `.associated_columns`: Returns an array of `Column` objects for associated columns.
- `.associations`: Returns an array of `Association` objects.
- `.query`: Returns the configured search query string.
- `.ignore`: Returns an array of fields to ignore during searching.
- `.ranking_sql`: Returns the SQL string used for ranking, or nil if not defined.
- `.features`: Returns an array of enabled features.
- `.feature_options`: Returns a hash of options for the enabled features.
- `.order_within_rank`: Returns the ordering string for within-rank sorting, or nil if not defined.
```
--------------------------------
### Define Valid Search Features
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Demonstrates the correct syntax for specifying single, multiple, or configured features for PostgreSQL full-text search, trigram similarity, and phonetic matching.
```ruby
# ✅ Valid features
using: :tsearch # PostgreSQL full text search
using: :trigram # Trigram similarity
using: :dmetaphone # Phonetic matching
# ✅ Multiple features
using: [:tsearch, :trigram, :dmetaphone]
# ✅ With options
using: {
tsearch: {dictionary: 'english'},
trigram: {threshold: 0.5}
}
```
--------------------------------
### Implement Double Metaphone Soundalike Search
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Utilize the `:dmetaphone` option for soundalike searches, which matches words that sound alike even if spelled differently. Ensure the `fuzzystrmatch` extension is installed and the `pg_search:dmetaphone` migration is run.
```ruby
class Word < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :that_sounds_like,
against: :spelling,
using: :dmetaphone
end
four = Word.create! spelling: 'four'
far = Word.create! spelling: 'far'
fur = Word.create! spelling: 'fur'
five = Word.create! spelling: 'five'
Word.that_sounds_like("fir") # => [four, far, fur]
```
--------------------------------
### Get Highlighted Search Results with pg_search_highlight
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/03_pg_search_model.md
Retrieve highlighted search results where matching terms are wrapped in HTML tags. This requires `.with_pg_search_highlight` to be chained and the `:tsearch` feature with `:highlight` option configured. Returns raw HTML.
```ruby
results = Article.search("ruby").with_pg_search_highlight
results.first.pg_search_highlight # => "...learn ruby programming..."
```
--------------------------------
### Conditional Indexing: Multiple Conditions
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Apply multiple conditions for indexing records. Use `if` with an array of methods for positive conditions and `unless` with an array of methods for negative conditions. This example indexes blog posts only if they are published, not archived, and not unlisted.
```ruby
class BlogPost < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :body],
if: [:published?, :not_archived?],
unless: [:unlisted?]
def published?
published_at <= Time.now
end
def not_archived?
!archived
end
def unlisted?
unlisted
end
end
```
--------------------------------
### Index for Multiple/Weighted Columns with `pg_search`
Source: https://github.com/casecommons/pg_search/wiki/Building-indexes
When using multiple or weighted columns with `pg_search`, create a single GIN index that includes the `setweight` function for each column. This ensures efficient searching across all specified fields.
```sql
CREATE INDEX "ts_vector_index_on_pages" ON "pages" USING gin (
setweight(to_tsvector('english', coalesce("pages"."name"::text, '')), 'A') ||
setweight(to_tsvector('english', coalesce("pages"."keywords"::text, '')), 'B') ||
setweight(to_tsvector('english', coalesce("pages"."body"::text, '')), 'C')
)
```
--------------------------------
### Global Document Search with Chaining
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/04_document.md
Demonstrates how to chain ActiveRecord methods with a global document search. This allows for more specific filtering and result manipulation.
```ruby
# Basic search
PgSearch::Document.search("python")
```
```ruby
# With chaining
PgSearch::Document.search("ruby")
.where(searchable_type: "Article")
.limit(5)
.includes(:searchable)
```
--------------------------------
### Custom Rebuild Method Implementation
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/05_multisearch.md
Override the default rebuilding process with a custom SQL implementation. This provides full control over how search documents are generated and updated.
```ruby
class Movie < ActiveRecord::Base
include PgSearch::Model
belongs_to :director
def director_name
director.name
end
multisearchable against: [:name, :director_name]
# Custom implementation - uses efficient SQL
def self.rebuild_pg_search_documents
connection.execute <<~SQL.squish
INSERT INTO pg_search_documents (searchable_type, searchable_id, content, created_at, updated_at)
SELECT 'Movie' AS searchable_type,
movies.id AS searchable_id,
CONCAT_WS(' ', movies.name, directors.name) AS content,
now() AS created_at,
now() AS updated_at
FROM movies
LEFT JOIN directors ON directors.id = movies.director_id
SQL
end
end
PgSearch::Multisearch.rebuild(Movie) # Uses the custom implementation
```
--------------------------------
### Accessing Configuration Columns
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/06_configuration.md
Retrieves all Column objects, including regular and associated columns, from a configuration instance.
```ruby
config = Configuration.new({
against: [:title, :body],
associated_against: { author: :name }
}, Article)
config.columns # => Array of Column objects
```
--------------------------------
### Configure Highlight Options for Search Results
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Use `.with_pg_search_highlight` to access the `pg_highlight` attribute for each object. This allows customization of highlight tags, minimum/maximum words, and fragment delimiters.
```ruby
class Person < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :search,
against: :bio,
using: {
tsearch: {
highlight: {
StartSel: '',
StopSel: '',
MinWords: 123,
MaxWords: 456,
ShortWord: 4,
HighlightAll: true,
MaxFragments: 3,
FragmentDelimiter: '…'
}
}
}
end
Person.create!(:bio => "Born in rural Alberta, where the buffalo roam.")
first_match = Person.search("Alberta").with_pg_search_highlight.first
first_match.pg_search_highlight # => "Born in rural Alberta, where the buffalo roam."
```
--------------------------------
### Configure Multiple Search Techniques
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Use the :using option to specify multiple search techniques like tsearch, trigram, and dmetaphone for a single search scope.
```ruby
class Beer < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :search_name, against: :name, using: [:tsearch, :trigram, :dmetaphone]
end
```
--------------------------------
### Custom Highlight Styling Options
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/13_common_patterns.md
Customize highlighting with options like word limits and fragment delimiters.
```ruby
pg_search_scope :search,
against: :content,
using:
{
tsearch: {
highlight: {
StartSel: '',
StopSel: '',
MaxWords: 100,
MinWords: 10,
MaxFragments: 3,
FragmentDelimiter: '…'
}
}
}
```
--------------------------------
### Run Automated Tests
Source: https://github.com/casecommons/pg_search/blob/master/CONTRIBUTING.md
Execute the project's automated tests using Rake. This can be done directly or via Bundler binstubs.
```bash
bundle exec rake
```
```bash
bin/rake
```
--------------------------------
### Providing Required Options
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Correctly configure search scopes by including the required :against, :associated_against, or :tsvector_column options.
```ruby
# ✅ Correct: Include :against
pg_search_scope :search, against: :title
```
```ruby
# ✅ Correct: Use :associated_against instead
pg_search_scope :search, associated_against: {author: :name}
```
```ruby
# ✅ Correct: Use tsvector_column
pg_search_scope :search,
using: {tsearch: {tsvector_column: 'my_column'}}
```
--------------------------------
### Create Multisearch Index and Model Scope
Source: https://github.com/casecommons/pg_search/wiki/Building-indexes
To use `multisearchable`, first add the appropriate GIN index to `pg_search_documents`. Then, configure your model with `multisearchable` and define a scope to facilitate searching.
```ruby
add_index :pg_search_documents, %[to_tsvector('simple', coalesce("pg_search_documents"."content"::text, ''))], using: :gin, name: "index_pg_search_documents_on_content"
```
```ruby
class User < ApplicationRecord
multisearchable(
against: [:name]
)
scope :full_text_search_for, -> (term) do
joins(:pg_search_document).merge(
PgSearch.multisearch(term).where(searchable_type: klass.to_s)
)
end
end
```
--------------------------------
### Create GIN or GIST Index for Full-Text Search
Source: https://github.com/casecommons/pg_search/wiki/Building-indexes
Use GIN or GIST indexes for full-text search. Identify the relevant SQL operator (% or @@) and the operand that is not the query to define the index expression.
```sql
CREATE INDEX my_cool_index ON my_cool_table USING gist (([expression]));
```
```sql
CREATE INDEX my_cool_index ON my_cool_table USING gist (([expression]) gist_trgm_ops);
```
--------------------------------
### Generate PgSearch Multisearch Migration
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/04_document.md
Run this command to generate the migration file for the `pg_search_documents` table, which is required for multisearch functionality.
```bash
rails generate pg_search:migration:multisearch
rake db:migrate
```
--------------------------------
### Define Ranking Algorithm (`ranked_by`)
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/06_configuration.md
Specify how search results should be ranked using SQL expressions. Placeholders for feature names are expanded to their respective ranking SQL.
```ruby
ranked_by: ":trigram"
```
```ruby
ranked_by: ":dmetaphone + (0.25 * :trigram)"
```
```ruby
ranked_by: "(articles.created_at DESC) + (:tsearch * 2)"
```
--------------------------------
### Configure Dictionary for Stemming in Ruby
Source: https://github.com/casecommons/pg_search/blob/master/README.md
Use the 'english' dictionary for stemming to match word variants, or 'simple' for no stemming. The 'simple' dictionary is the default if none is specified.
```ruby
class BoringTweet < ActiveRecord::Base
include PgSearch::Model
pg_search_scope :kinda_matching,
against: :text,
using: {
tsearch: {dictionary: "english"}
}
pg_search_scope :literally_matching,
against: :text,
using: {
tsearch: {dictionary: "simple"}
}
end
sleep = BoringTweet.create! text: "I snoozed my alarm for fourteen hours today. I bet I can beat that tomorrow! #sleep"
sleeping = BoringTweet.create! text: "You know what I like? Sleeping. That's what. #enjoyment"
sleeps = BoringTweet.create! text: "In the jungle, the mighty jungle, the lion sleeps #tonight"
BoringTweet.kinda_matching("sleeping") # => [sleep, sleeping, sleeps]
BoringTweet.literally_matching("sleeps") # => [sleeps]
```
--------------------------------
### Paginated Multisearch with Kaminari
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/02_pg_search_module.md
Apply pagination to multisearch results using a library like Kaminari. Allows for efficient display of large result sets.
```ruby
PgSearch.multisearch("ruby").page(2).per(20)
```
--------------------------------
### Handle ArgumentError for Unknown Search Features
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Use only supported features in the `using` option to avoid ArgumentErrors. Refer to the 'Supported Features' section for valid options.
```ruby
# ❌ Wrong: Unknown feature
pg_search_scope :search, against: :title, using: :unknown_feature
Article.search("test")
# => ArgumentError: Unknown feature: unknown_feature
```
--------------------------------
### Search with Highlighting Configuration
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md
Enable text highlighting in search results by configuring `highlight` options within the `using` hash for `pg_search_scope`. The highlighted snippet is available via `pg_search_highlight`.
```ruby
pg_search_scope :search,
against: :content,
using: { tsearch: { highlight: { StartSel: '', StopSel: '' } } }
```
```ruby
results = Article.search("query").with_pg_search_highlight
```
```ruby
results.first.pg_search_highlight # => "...learn ruby..."
```
--------------------------------
### PgSearch Module Methods
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md
Provides methods for initiating multisearch queries, managing searchability, and accessing configuration options.
```APIDOC
## PgSearch Module
### `multisearch(query)`
**Description**: Executes a multisearch query against the configured models.
**Method**: Not applicable (Module method)
**Parameters**:
- `query` (String) - The search query string.
**Returns**: Relation - A relation of matching documents.
### `disable_multisearch { block }`
**Description**: Temporarily disables multisearch functionality within the provided block.
**Method**: Not applicable (Module method)
**Parameters**:
- `block` (Proc) - Code to execute with multisearch disabled.
**Returns**: void
### `multisearch_enabled?`
**Description**: Checks if multisearch is currently enabled.
**Method**: Not applicable (Module method)
**Returns**: Boolean - True if multisearch is enabled, false otherwise.
### Accessors
- `multisearch_options`: Accesses the multisearch configuration options.
- `unaccent_function`: Accesses the unaccent function used for accent-insensitive searching.
```
--------------------------------
### Perform Multisearch Using Customer Instance
Source: https://github.com/casecommons/pg_search/wiki/Segregating-search-documents-(multi-tenancy)
Perform a multisearch query directly on a customer instance using the custom multisearch method. This leverages the customer-scoped search functionality.
```ruby
customer.multisearch('MyWidget')
```
--------------------------------
### Checking for Highlight Availability
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/12_errors.md
Provides an alternative solution by checking if the `pg_search_highlight` method is available on a result before attempting to access it.
```ruby
result = Article.search("ruby").with_pg_search_highlight.first
if result.respond_to?(:pg_search_highlight, true)
puts result.pg_search_highlight
end
```
--------------------------------
### Feature Instantiation for Search
Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/09_scope_options.md
Instantiates feature classes based on the feature name, mapping to specific feature implementations like TSearch, Trigram, or DMetaphone. Requires query, options, columns, model, and normalizer.
```ruby
feature_class = FEATURE_CLASSES[feature_name]
# Maps to:
# :tsearch => Features::TSearch
# :trigram => Features::Trigram
# :dmetaphone => Features::DMetaphone
feature = feature_class.new(
query,
feature_options[feature_name],
columns,
model,
normalizer
)
```