Ransack search, how to search for each word by splitting input search parameter
Asked Answered
L

2

5

I am currently experimenting using the ransack gem to conduct a search on a model in Rails. As it stands I am using the basic setup.

Controller:

def index
  @q = Person.search(params[:q])
  @people = @q.result(:distinct => true)
end

View:

<%= search_form_for @q do |f| %>
   <%= f.label :name_cont %>
   <%= f.text_field :name_cont %>
   <%= f.submit %>
<% end %>

I have managed to find lot of information about conducting searches on multiple fields, however, I haven't managed to find anything to help me to split up the :q parameter and thereby enable me to search for each of the (unknown quantity of) words in the search string entered in the form of search for ??? AND ??? AND ??? ..., rather than searching for the entire string in one section

Is anybody able to point me in the right direction?

Locke answered 25/3, 2013 at 9:47 Comment(0)
L
1

Having spent a chunk of time looking into this with no results, I opted for a custom, non-ransack option which works perfectly well.

In View.html.erb

<%= form_tag siteindex_search_allproducts_path, :method => 'get' do %>
    <b>Search: </b> <%= text_field_tag :search, params[:search] %>
    <%= submit_tag "Search", :name => nil %>
<% end %>

In Controller

@findproducts = Allproduct.order('price ASC').search(params[:search])

In model.rb

def self.search(*args)
   return [] if args.blank?
   cond_text, cond_values = [], []
   args.each do |str|
       next if str.blank?  
       cond_text << "( %s )" % str.split.map{|w| "product_name LIKE ? "}.join(" AND ")
       cond_values.concat(str.split.map{|w| "%#{w}%"})
    end
    all :conditions =>  [cond_text.join(" AND "), *cond_values]
end
Locke answered 9/4, 2013 at 19:52 Comment(1)
I am trying this, but I'm getting an error on the last line "wrong number of arguments (1 for 0)"Auspicate
G
7

Here's an answer that uses a custom Ransack predicate:

# config/initializers/ransack.rb

Ransack.configure do |config|
  config.add_predicate 'has_any_term',
  arel_predicate: 'matches_any',
  formatter: proc { |v| v.scan(/\"(.*?)\"|(\w+)/).flatten.compact.map{|t| "%#{t}%"} },
  validator: proc { |v| v.present? },
  type: :string
end

Ransack.configure do |config|
  config.add_predicate 'has_every_term',
  arel_predicate: 'matches_all',
  formatter: proc { |v| v.scan(/\"(.*?)\"|(\w+)/).flatten.compact.map{|t| "%#{t}%"} },
  validator: proc { |v| v.present? },
  type: :string
end

The search form would use the custom predicate as such:

# In your view

# to search for any of the terms existing in my_field 
=search_form_for @search do |f|
  =f.search_field  :my_field_has_any_term


# to search for all of the terms existing in my_field 
=search_form_for @search do |f|
  =f.search_field  :my_field_has_every_term

Double-quoted terms will be recognized automatically.

Grating answered 12/8, 2016 at 19:15 Comment(2)
I'd propose to use [[:alpha]] instead of \w in the regex though, as otherwise this will split words with Umlauts in them.Cultigen
(or [[:alnum:]] if you want to include numbers as well)Cultigen
L
1

Having spent a chunk of time looking into this with no results, I opted for a custom, non-ransack option which works perfectly well.

In View.html.erb

<%= form_tag siteindex_search_allproducts_path, :method => 'get' do %>
    <b>Search: </b> <%= text_field_tag :search, params[:search] %>
    <%= submit_tag "Search", :name => nil %>
<% end %>

In Controller

@findproducts = Allproduct.order('price ASC').search(params[:search])

In model.rb

def self.search(*args)
   return [] if args.blank?
   cond_text, cond_values = [], []
   args.each do |str|
       next if str.blank?  
       cond_text << "( %s )" % str.split.map{|w| "product_name LIKE ? "}.join(" AND ")
       cond_values.concat(str.split.map{|w| "%#{w}%"})
    end
    all :conditions =>  [cond_text.join(" AND "), *cond_values]
end
Locke answered 9/4, 2013 at 19:52 Comment(1)
I am trying this, but I'm getting an error on the last line "wrong number of arguments (1 for 0)"Auspicate

© 2022 - 2024 — McMap. All rights reserved.