Hulihan Applications
about projects portfolio services contact_us

Feature #120

avatar

Make Advanced Search Better

Added by Dave Hulihan 161 days ago. Updated 124 days ago.

Status:Closed Start:02/20/2010
Priority:High Due date:
Assigned to:- % Done:

100%

Category:- Spent time: 2.00 hours
Target version:0.3.3

Description

We should incorporate a cooler advanced search. One step I was thinking is to add a "search_type" field to each Feature. This field can be "text_input" for a text box, "select_existing" for a select box with existing values from different items, "comparison" for a comparison between two values, etc.

History

Updated by Dave Hulihan 155 days ago

avatar
  • Priority changed from Normal to High

Updated by Dave Hulihan 144 days ago

avatar
  • Target version changed from 0.3.2 to 0.3.3

Updated by Dave Hulihan 139 days ago

avatar

We've beefed up Opal's Advanced search quite a bit!

  • First, we've implemented the new Feature Search Types, which allows for the searching user to search for feature values in different ways(like text-field searching, drop-down grouped values, etc.). This gives the Advanced Search a better feel and lets users search for items more effectively.
  • We've also improved the Advanced Search's security features quite a bit. Now there's better SQL Sanitiation that prevents again SQL Injection Attacks. Since we're accepting several different forms of input(drop-down boxes, text fields, etc.), we needed to make sure no one can inject any Malicious Code into the search. This becomes increasingly difficult since we're not just searching for Item attributes, but attributes from several other ActiveRecord models also!

Updated by Dave Hulihan 139 days ago

avatar

Just to clarify, I mentioned that Opal's advanced search now performs sql sanitation for an unlimited number of different conditions for FeatureValues. Since we don't know how many Features a user is going to search for, we need to make the sanitiation dynamic. How can this be done in Rails, you might ask? Well, I used ActiveRecord's Conditions Sanitizer, and since you can pass conditions into ActiveRecord's find in a variety of Formats, we chose the "String of Conditions, Hash of Values" format, it looks like this:

  Company.find(:first, :conditions => [
    "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
    { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
  ])

Using this format, I created a loop that added all selected Features(indexed by id) to a string, and added their associated values to a hash, also indexed by the Feature's id. Here's a look at what I did in code:

 values_array = Array.new # array to contain strings of certain conditions, ie: ["x = :x_value", "y LIKE :y_value"], which we will then join with the appropriate conjunction, ie: conditions.join(" AND ")  to create the required string
 values_hash = Hash.new # hash to contain values, ie: {:x_value => "someValue", :y_value => "%someValue%"}   
 for i in 1..params[:feature].size # loop through for every feature value, create a set of ActiveRecord conditions
     num_of_features_to_search = 1 # increment number of features to search  
     # Create MySQL Conditions for Matching Items with these Features         
      values_array << "value = :feature_#{i}" # add string to array that conforms to ActiveRecords Conditions format, ie: "x = :x_value" 
      values_hash["feature_#{i}".to_sym] = "#{params[:feature][i.to_s]["value"]}"        
     end 
  end 
 matching_feature_values = PluginFeatureValue.find(:all, :conditions => [values_array.join(" AND "), values_hash]) # convert conditions array to string seperated by AND db operator        

Using this format, ActiveRecord handles SQL sanitation, and we can search for any number of features safely.

Updated by Dave Hulihan 139 days ago

avatar
  • % Done changed from 0 to 80

Looking Good, just a little more testing before I can sign off on this...

Updated by Dave Hulihan 127 days ago

avatar

Ahh! The new injection-proof code listed above for the New Feature search will only work with a OR-type lookup in mysql. This means that all items with one matching feature(out of all selected) will be listed. This is not what we want!

Updated by Dave Hulihan 127 days ago

avatar
  • % Done changed from 80 to 100

I've fixed the OR lookup problem by creating a hash of Item IDs found that match each feature selected. I then took that hash and selected only the common Item IDs that had a match for EVERY feature, using this function:

  def get_common_elements_for_hash_of_arrays(hash) # get an array of common elements contained in a hash of arrays, for every array in the hash.
    #example_hash = {:feature_0 => [1,2,3], :feature_1 => [2,4,5], :feature_2 => [2,5,6] } # for testing
    return hash.values.inject{|acc,elem| acc & elem} # inject & operator into hash values.
  end

Now we're looking pretty good.

Updated by Dave Hulihan 124 days ago

avatar
  • Status changed from New to Closed

Also available in: Atom PDF



Hulihan Applications © 2007-2009
No portion of this site may be copied, altered, duplicated or otherwise used without the express written approval of Hulihan Applications.