Recently, I started using the ransack gem (https://github.com/ernie/ransack) for searching in one of my apps. I’m putting this here as an example, in case I ever need to make any more changes. The basics of ransack are pretty easy to do and work decently well. First step, add a search method to your controller. It should look something like this:

def search
    @q = Board.search(params[:q])
    @boards = @q.result
    @count = @boards.count
  end

We have @count because we’d like to be able to show the number of results on the page.

Next we have a search view. The start of the form looks like this:

<%= search_form_for @q, :url => search_boards_path, :html => {:method => :post} do |f| %>
	<%= render 'status_fields' %>

In my example, we have a number of different fields that we are searching. With ransack, this is easy because they have a number of different built-in predicates that can be used. So here are two example searches that would be in the form above.

<%= f.label :temp_cycling_true, 'Temperature has been cycled' %>
<%= f.check_box :temp_cycling_true %> <%= f.label :r3v3_lteq, 'R3V3 <= '%> <%= f.text_field :r3v3_lteq, :size => 5 %>

In the first line, I have a checkbox that checks whether the field temp_cycling is set to true. The second line checks that the field r3v3 is less than or equal to the value entered in the box.

I have about 15 of these searches that I use in my search field. However, there was one more search that I wanted to be able to do that was giving me problems.

I have a field called status and it can have one of four different values: good, untested, repaired or broken. I wanted to be able to search, say the good or repaired ones. So, I couldn’t use a text field to type in a value. The way to do this was to have checkboxes for each possible value and then OR them in the search query. I looked at the advanced example provided by the ransack creator, tried to modify it to meet my needs and completely failed. However, I did learn quite a bit about how the syntax of the queries. (I suppose if I were a better programmer, I could have learned this by reading the code. Alas, I had to use the trial-and-error method.) The params[:q] gives the entire query that is used. In this query, there are other letters: g = grouping m = and or or c = combinator p = predicate a = arguments v = values which are all hashes that make up the query. I found that what I wanted to do was add an or grouping to my other search results. I did this using a combination of hidden fields and check boxes. In my main search partial, I render another partial caled status_fields. \_status\_fields_html.erb
Status:
<%= hidden_field_tag 'q[g][0][m]', 'or'%> <% ['good', 'repaired', 'untested', 'broken'].each_with_index do |s, i| %> <%= hidden_field_tag "q[g][0][c][#{i}][a][0][name]", 'status'%> <%= hidden_field_tag "q[g][0][c][#{i}][p]", 'eq' %> <% if params[:q].nil? %> <%= check_box_tag "q[g][0][c][#{i}][v][0][value]", "#{s}" %> <% else %> <%= check_box_tag "q[g][0][c][#{i}][v][0][value]", "#{s}", params[:q][:g][:"0"][:c][:"#{i}"][:v] ? true : false %> <% end %> <%= label_tag "q[g][0][c][#{i}][v][0][value]", "#{s}" %>
<% end %>
Line 2 is a hidden field that specifies that this grouping should be or’d together. In line 3 I start a loop that goes through each of my possible values and generates two hidden tags. Line 4 sets the hash “c”=>{“0″=>{“a”=>{“0″=>{“name”=>”status”}} and line 5 adds “p”=>”eq”. Lines 6-10 are putting the check boxes with the options out. The if is necessary for the times when you haven’t yet submitted a search. In these cases, none of the boxes will be checked. After you have submitted a search, if a box was used previously, it should be set so you can see what you were searching for. So this bit, adds “v”=>{“0″=>{“value”=>”good”}}} to the query, if the good box was checked. For a final example, here is what my query looks like when I search for just the good or repaired boards.
Parameters: {"utf8"=>"?", 
"authenticity_token"=>"66vdGQSBRD0Pr+8xbIlXim9mkkWkzMUukAvy20QEbFY=", 
"q"=>{"g"=>{"0"=>{"m"=>"or", "c"=>{
"0"=>{"a"=>{"0"=>{"name"=>"status"}}, "p"=>"eq", "v"=>{"0"=>{"value"=>"good"}}}, 
"1"=>{"a"=>{"0"=>{"name"=>"status"}}, "p"=>"eq", "v"=>{"0"=>{"value"=>"repaired"}}}, 
"2"=>{"a"=>{"0"=>{"name"=>"status"}}, "p"=>"eq"}, 
"3"=>{"a"=>{"0"=>{"name"=>"status"}}, "p"=>"eq"}}}}, 
"board_number_eq"=>"", "temp_cycling_true"=>"0", "temp_cycling_false"=>"0",
 "dc_current_without_firmware_gteq"=>"", "dc_current_without_firmware_lteq"=>"", 
"r3v3_gteq"=>"", "r3v3_lteq"=>"", "r2v5_gteq"=>"", "r2v5_lteq"=>"", "r1v2_gteq"=>"", 
"r1v2_lteq"=>"", "dc_current_with_firmware_gteq"=>"", "dc_current_with_firmware_lteq"=>"",
 "rod_slot_eq"=>"", "rod_crate_cont"=>"", "ftk_fiber_eq"=>"", 
"ftk_fiber_destination_cont"=>"", "daq_fiber_eq"=>"", "daq_fiber_destination_cont"=>"", 
"note_cont"=>""}, "commit"=>"Search"}
I am 100% sure that there’s a better way to do this, but a better rails programmer will have to tell me what it is. I tried creating my own predicate. But whenever I used a checkbox, I could only get values = 1. I couldn’t find a way to make the value = ‘good’ or ‘repaired’.

I found the correct way to do this and I’ve written a blog post about it here.