Skip to content

Commit

Permalink
Contact.text_search is now using arel. Can rely on proper query sanit…
Browse files Browse the repository at this point in the history
…ization.
  • Loading branch information
steveyken committed Nov 24, 2012
1 parent 99e3d73 commit 7e080c9
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
18 changes: 12 additions & 6 deletions app/models/entities/contact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,23 @@ class Contact < ActiveRecord::Base
scope :assigned_to, lambda { |user| { :conditions => ["assigned_to = ?", user.id ] } }

scope :text_search, lambda { |query|
query = query.gsub(/[^@\w\s\-\.'\p{L}]/u, '').strip
t = Contact.arel_table
# We can't always be sure that names are entered in the right order, so we must
# split the query into all possible first/last name permutations.
name_query = if query.include?(" ")
query.name_permutations.map{ |first, last|
"(upper(first_name) LIKE upper('%#{first}%') AND upper(last_name) LIKE upper('%#{last}%'))"
}.join(" OR ")
scope, *rest = query.name_permutations.map{ |first, last|
t[:first_name].matches("%#{first}%").and(t[:last_name].matches("%#{last}%"))
}
rest.map{|r| scope = scope.or(r)} if scope
scope
else
"upper(first_name) LIKE upper('%#{query}%') OR upper(last_name) LIKE upper('%#{query}%')"
t[:first_name].matches("%#{query}%").or(t[:last_name].matches("%#{query}%"))
end
where("#{name_query} OR upper(email) LIKE upper(:m) OR upper(alt_email) LIKE upper(:m) OR phone LIKE :m OR mobile LIKE :m", :m => "%#{query}%")

other = t[:email].matches("%#{query}%").or(t[:alt_email].matches("%#{query}%"))
other = other.or(t[:phone].matches("%#{query}%")).or(t[:mobile].matches("%#{query}%"))

where( name_query.nil? ? other : name_query.or(other) )
}

uses_user_permissions
Expand Down
41 changes: 41 additions & 0 deletions spec/models/entities/contact_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,45 @@
describe "permissions" do
it_should_behave_like Ability, Contact
end

describe "text_search" do

before(:each) do
@contact = FactoryGirl.create(:contact, :first_name => "Bob", :last_name => "Dillion", :email => 'bob_dillion@example.com', :phone => '+1 123 456 789')
end

it "should search first_name" do
Contact.text_search('Bob').should == [@contact]
end

it "should search last_name" do
Contact.text_search('Dillion').should == [@contact]
end

it "should search whole name" do
Contact.text_search('Bob Dillion').should == [@contact]
end

it "should search whole name reversed" do
Contact.text_search('Dillion Bob').should == [@contact]
end

it "should search email" do
Contact.text_search('example').should == [@contact]
end

it "should search phone" do
Contact.text_search('123').should == [@contact]
end

it "should not break with a single quote" do
contact2 = FactoryGirl.create(:contact, :first_name => "Shamus", :last_name => "O'Connell", :email => 'bob_dillion@example.com', :phone => '+1 123 456 789')
Contact.text_search("O'Connell").should == [contact2]
end

it "should not break on special characters" do
Contact.text_search('@$%#^@!').should == []
end

end
end

0 comments on commit 7e080c9

Please sign in to comment.