pg_search icon indicating copy to clipboard operation
pg_search copied to clipboard

How would I search against a string that has an ampersand?

Open krzkrzkrz opened this issue 5 years ago • 1 comments

For example. I have two products with the following names:

Mac & cheese
Mac and cheese

Ideally, if one were to do Product.search_by_name("mac &") or Product.search_by_name("mac and"), then both products above should be in the results

krzkrzkrz avatar May 14 '20 16:05 krzkrzkrz

I'm not related to the development of this specific plugin, but I would be looking into the direction of making the data you store all use either one or the other. If that isn't possible you could do the following thing:

  • Dynamically replacing all occurrences of "&" with "and" in a postgres select statement (https://www.postgresql.org/docs/9.3/functions-string.html is a nice place to start if you want to build such queries) while searching. this makes sure that your postgres search will always find "and"s
  • wrap your Product.search_by_name(search) in a method like so:
def self.search(raw_search_string)
  refined_search_string = raw_search_string.gsub!('&', 'and')
  Product.search_by_name(refined_search_string)
end 

It's not perfect though :( If this is super important and your users run into a lot of "&" issues, you could alternatively add an extra column called simplified_name that you populate in a before_save hook like so:

class Product < ApplicationRecord
  include PgSearch::Model
  pg_search_scope :search_by_simplified_name,
                  against: %[name],
                  using: {
                    tsearch: { prefix: true }
                  }

  before_save :populate_simplified_name
  
  def self.search_by_name(query)
    simplified_name = Product.simplify_name(query)
    Product.search_by_simplified_name(simplified_name)
  end
  
  # you could put this method in a helper module
  def self.simplify_name(query)
    return '' unless query.present?
    
    name.gsub('&', 'and')
    # Other sensitization you'd like to do
  end

  private
  
  def populate_simplified_name
    self.simplified_name = Product.simplify_name(name).presence
  end
end

HendrikPetertje avatar Jan 05 '21 14:01 HendrikPetertje