### HighlightOptions Configuration Example Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/11_types.md Provides an example of configuring highlight options for the ts_headline SQL function, specifying custom markup, word limits, and fragment delimiters. ```ruby { StartSel: '', StopSel: '', MaxWords: 50, MinWords: 5, MaxFragments: 3, FragmentDelimiter: '…' } ``` -------------------------------- ### Setup DMetaphone PostgreSQL Extension Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/07_features.md Generate and run the migration to set up the DMetaphone function in your PostgreSQL database. This is a one-time setup step. ```bash rails generate pg_search:migration:dmetaphone rake db:migrate ``` -------------------------------- ### Install PgSearch Gem Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/INDEX.md Install the pg_search gem using Bundler or directly. This is the first step to integrating search functionality. ```bash gem install pg_search # or in Gemfile: gem 'pg_search' ``` -------------------------------- ### DMetaphone Normalization Examples Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/10_normalizer.md Illustrates how to apply DMetaphone normalization, with and without accent normalization, to SQL expressions. ```ruby # Without normalization: column_sql # With dmetaphone normalization: pg_search_dmetaphone(column_sql) # With both dmetaphone and accent normalization: pg_search_dmetaphone(regexp_replace(unaccent(column_sql), '[...]', '', 'g')) ``` -------------------------------- ### Basic Multisearch Example Source: https://github.com/casecommons/pg_search/blob/master/_autodocs/03_pg_search_model.md Demonstrates how to set up a model for multisearch and perform a basic search query. Only records matching the search criteria will be returned. ```ruby class BlogPost < ActiveRecord::Base include PgSearch::Model multisearchable against: [:title, :body] end post = BlogPost.create!(title: "Ruby Tips", body: "...") PgSearch.multisearch("Ruby") # => [#] ``` -------------------------------- ### 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 ) ```