Search code examples
ruby-on-railspluginssearchlogicremoving-whitespace

rails trim whitespace from searchlogic text field


This works:

Baseline Controller

@search = Baseline.search(params[:search])

@baselines = @search.paginate :page => params[:page], :per_page => params[:per_page]

baseline index view

<% form_for @search do |f| %>
  <%= f.text_field :baseline_name_like_or_description_like %>
  <%= submit_tag 'Search' %>
<% end %>

Where would I trim the leading and trailing whitespace in the text_field? Could I use a .strip! somewhere?


Solution

  • Nick, surprisingly, it's quite difficult to find information on advanced Searchlogic techniques. Sanitization has been particularly difficult for me to deal with.

    Here's a pretty nifty (and quick) way to deal with your issue.

    controller

    stays the same

    views/baselines/index.html.erb

    <% form_for @search do |f| %>
      <%= f.text_field :keywords %>
      <%= submit_tag 'Search' %>
    <% end %>
    

    models/baseline.rb

    class Baseline < ActiveRecord::Base
      scope_procedure :keywords, lambda { |query|
        baseline_name_like_or_description_like(query.strip)
      }
    end
    

    Extras

    I'm excited to share the other cool things I've learned with Searchlogic, so I'll share them here.

    First, with very little work, you can power-up that keywords scope_procedure with minimal effort.

    scope_procedure :keywords, lambda { |query|
      baseline_name_like_any_or_description_like_any(query.strip.split(/\s+/))
    }
    

    Note the addition of the any operator to each named_scope

    This will allow you to enter searches like "foo bar" and it will match baseline_names like "i can foo haz bar" or "bar time, foo!" This would even match a Baseline if the name was "foo" and the description was "bar"; point being, you get tons of extra control if you use scope_procedure instead of a predefined named_scope in your Searchlogic forms.

    Second, you can sanitize your search forms with a little extra effort. This one took quite a while to figure out, but I decided to create a subclass of the Searchlogic::Search class. Check it out:

    models/baseline_search.rb

    class BaselineSearch < Searchlogic::Search
      def initialize(params, klass, current_scope)
    
        allowed_params = [:keywords, :name_like_any, :foo_equals, :order]
    
        conditions = {}
    
        for x in allowed_params 
          conditions[x] = params[x] unless params[x].blank?
        end
    
        super(klass, current_scope, conditions)
      end
    end
    

    If you're wondering where I found that initialize method signature, check Searchlogic::Search

    Now, instead of invoking Searchlogic::Search on your model, you need to create a simple override in your baseline.rb. Here, we'll implement our own Searchlogic::Search::Implementation

    models/baseline.rb

    class Baseline < ActiveRecord::Base
    
      # cool scope procedures
      # ...
    
      def self.search(params={})
        BaselineSearch.new(params || {}, self, scope(:find))
      end
    end
    

    Now, when you call Baseline.search(params[:search]), it will invoke a new BaselineSearch instead of the Searchlogic::Search default. The cool thing here is, if you want to skip using your BaselineSearch, you can call Baseline.searchlogic(params[:search]) to use the Searchlogic default instead.