In my latest rails app, I want to compare a number of objects. My first solution was to create a new search page with a form on it.

<%= form_tag("/compare_ids", :method => 'get') do %>
	<%= text_area_tag(:z, nil, :size => "20x6") %>
	<%= submit_tag("Compare") %>
<% end %>

The objects in question are plates, identified by a serial number. So, the user should type in the serial numbers (one per line) in the text area in the form. My compare_ids method then takes the data from the form (it comes in as a string) and finds each plate. The key is this method I have in the model. The method takes the string and breaks it up by the line breaks and then just cycles through to make a string to use in a find_by_sql command.

def self.get_plates(list)
    @ids = list.split(/\r\n/)
    @ids.each_with_index do |id, index|
      if(index == 0)
        @string = "(plates.serial_number = '#{id}')"
      else
        @string << " OR (plates.serial_number = '#{id}')"
      end
    end
    plates = find_by_sql("select plates.* from plates where (#{@string})")
  end

This worked, but I wasn’t that happy with it. Mainly because the serial numbers are kind of long and typing them in will lead to mistakes for sure.

I have another page where I list all our current plates along with their current location. I thought I should be able to make this page into a form where I put a checkbox in front of each plate. Then, the user just needs to check those to compare and hit the compare button. A much easier way of comparing a large number of plates.

My problem though was in setting up the form. I kept getting urls of the form z=123&z=456&z=789…, which lead to the value of z being the last one in the list. I wanted a way to get a string or array of values with all the values for z. Here’s how I solved it.

<%= form_tag("/compare_ids", :method => 'get') do %>
  <% @plates.each do |plate| %>
    <%= check_box_tag 'z[]', "#{plate.serial_number}"%> <%= link_to "#{plate.serial_number}", plate %>
  <% end %>
<% end %>

The key here is the check_box_tag name is z[] and not just z. This will return an array. So my get_plates method above needs to be modified a little so that it can handle either a string or array. Here’s the final version.

def self.get_plates(list)
    # Given a string/array of incom serial numbers, get the info for those plates
    # The compare on plates#index returns an array, from advanced search it's a string
    if list.class == String
      @ids = list.split(/\r\n/)
    else
      @ids = list
    end
    @ids.each_with_index do |id, index|
      if(index == 0)
        @string = "(plates.serial_number = '#{id}')"
      else
        @string << " OR (plates.iserial_number = '#{id}')"
      end
    end
    plates = find_by_sql("select plates.* from plates where (#{@string})")
  end

It took me a while to figure this all out, but I’m really glad I did. My previous post on using ransack and check boxes is something I want to go back to because I think this is a much better way of handling things. I also have some more ransack stuff to do on this app and I think this will help.