Multi Search with Ferret, Pagination and Sorting

Posted on December 28, 2007
1
2
3
4
5
6
7
8
9
10
11
12
13


  def self.paginating_ferret_search(options)
    offset = (options[:current].to_i - 1) * options[:page_size]
    limit = options[:page_size]
    order = options[:order]
    count = total_hits(options[:q])
    PagingEnumerator.new(options[:page_size], count, false, options[:current], 1) do |page|
      res = find_with_ferret(options[:q], 
           {:offset => offset, :limit => limit, :sort => order})
    end
  end


This is the method in the controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


  def search
    #params[:d] is the direction of sorting
    if params[:d]
      sort_order = params[:c] + (params[:d] == 'down' ? ' DESC' : ' ASC')
    else
      sort_order = "name ASC"
    end
    current_page = (params[:page] ||= 1).to_i
    
    # check for each search field on the form 
    if params[:city] && !params[:city].blank?
      @city_query = "city:\"#{params[:city]}\""
      @city_label = "City: <blue>#{params[:city]}</blue>"
    end
    
    if params[:state] && !params[:state].blank?
      @state_query = "state:#{params[:state]}"
      @state_label = "State: <blue>#{params[:state]}</blue>"
      if @state_query.size != 2
        flash[:notice] = "State should be 2 Digits"
      end
    end
    
    if params[:zip] && !params[:zip].blank?
      @zip_code_query = "zip:#{params[:zip]}*"
      @zip_code_label = "Zip: <blue>#{params[:zip]}*</blue>"
    end
    
    if params[:name] && !params[:name].blank?
      @name_query = "name:#{params[:name]}"
      @name_label = "Name: <blue>#{params[:name]}</blue>"
    end
    
    # for ferret we cannot User "name ASC", have to be "name"
    if @city_query or @state_query or @zip_code_query or @keyword_query
    # params[:c] is the column name to sort
      if params[:c]
        sort_order = case params[:c]
          when "name"    then "name"
          when "city"       then "city"
          when "state"     then "state"
          when "zip"       then "zip"
          else "name"
        end
      else
        sort_order = "name"
      end
      
      # Conditions: can be either of both AND/OR
      @condition = "AND"
      # Queries for Ferret
      # My helper to build the query,
      @full_query = build_query(@full_query, @keyword_query,  @condition)
      @full_query = build_query(@full_query, @city_query,     @condition)
      @full_query = build_query(@full_query, @state_query,    @condition)
      @full_query = build_query(@full_query, @zip_query, @condition)
      # Labels  for flash[:notice]
      # I use comma to delimiter the labels in flash[:notice]
      @condition = ","
      @query_label = build_query(@query_label, @keyword_label,  @condition)
      @query_label = build_query(@query_label, @city_label,     @condition)
      @query_label = build_query(@query_label, @state_label,    @condition)
      @query_label = build_query(@query_label, @zip_label, @condition)
      
      # get the query
      @users = User.paginating_ferret_search({:q => @full_query, 
            :page_size => 100,
            :current => current_page, 
            :order => sort_order}
      )
      flash[:notice] = "<h3> Found #{@prospects.size} records for #{@query_label} </h3>"
    else
      # if no query, just return empty
      @User = []
   end
end

My application method, in application.rb add this method:

1
2
3
4
5
6
7
8
9
10
11
12
13


  def build_query(full_query, query, condition)
    if query
      if full_query && !full_query.empty?
        full_query = "#{full_query} #{condition} #{query}"
      else
        full_query = query
      end
    end 
    return full_query
  end  

in application_helper.rb I have this little helper I found in this site
it helps to make the links in the sorting columns in the views.. def sort_link(title, column, options = {}) condition = options[:unless] if options.has_key?(:unless) sort_dir = params[:d] == 'up' ? 'down' : 'up' link_to_unless condition, title, request.parameters.merge( {:c => column, :d =>
Comments
  1. AdamMarch 28, 2008 @ 09:22 PM

    Just a note that if you're on the latest versions of actsas_ferret and willpaginate then paginated ferret searches are as simple as this:

    @results = ActsAsFerret::find(params[:q], 
    [ModelA, ModelB, ModelC], 
    {:page => params[:page], :per_page => 25})
    

    And you can add conditions to do the search order

Post a comment
Comment