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.