#--- # Excerpted from "Advanced Rails Recipes", # published by The Pragmatic Bookshelf. # Copyrights apply to this code. It may not be used to create training material, # courses, books, articles, and the like. Contact us if you are in doubt. # We make no guarantees that this code is fit for any purpose. # Visit http://www.pragmaticprogrammer.com/titles/fr_arr for more book information. #--- module Searchable def searchable_by(*column_names) @search_columns = [] [column_names].flatten.each do |name| @search_columns << name end end def search(query, fields=nil, options={}) with_scope :find => { :conditions => search_conditions(query, fields) } do find :all, options end end def search_conditions(query, fields=nil) return nil if query.blank? fields ||= @search_columns # split the query by commas as well as spaces, just in case words = query.split(",").map(&:split).flatten binds = {} # bind symbols or_frags = [] # OR fragments count = 1 # to keep count on the symbols and OR fragments words.each do |word| like_frags = [fields].flatten.map { |f| "LOWER(#{f}) LIKE :word#{count}" } or_frags << "(#{like_frags.join(" OR ")})" binds["word#{count}".to_sym] = "%#{word.to_s.downcase}%" count += 1 end [or_frags.join(" AND "), binds] end end