简体   繁体   中英

How do I use ruby's find method to find people by the first letter in their first name and middle name

I have Ruby on Rails application that has a Person model that maps to a People table. The table includes first_name, middle_name and last_name as follows:

John Q. Doe
John H. Doe
Jane M. Doe
Jim R. Doe, Jr.
Jack Timothy Doe

Now, I need to perform finds against the table when my input is an abbreviation of a particular name derivation. The abbreviation is of the following form:

  • First initial of first name followed by a space
  • first initial of the middle name followed by a space (if there is a middle name)
  • full last name

For example:

find_by_abbreviated_name("J Q Doe") => would find the John Q. Doe record
find_by_abbreviated_name("J T Doe") => would find the Jack Timothy Doe record
find_by_abbreviated_name("J R Doe, Jr.") => Jim R Doe, Jr.

Is there a slick way in Ruby to do a find using the first letter of the first and middle names in conjunction with the full last name. I'm hoping I can come up with a way to do this so I don't have to add another field to the Person table.

So I think the problem you have to handle is that the format of the input will vary ... unless you can guarantee input elements. If middle is optional, and last may have multiple tokens, you have a challenge you have something you cannot parse reliably if it's passed as a single string:

John Doe Jr
John Doe, Jr.
John Quentin Doe
John Doe Worthington-Smythe

(many surnames have multiple parts, etc.)

So you could handle this by providing distinct input fields, by confirming ambiguous cases with the user, or trying several alternatives based on some rules or common cases. So let's wait on the parsing part and assume you have distinct inputs that are properly formatted (eg upper-cased single characters):

def find_by_abbreviated_name(fist_init, middle_init, last_name)
  if middle_init.blank?
    People.where("first LIKE ? AND middle LIKE ? and LAST like ?", "#{first_init}%", "#{middle_init}%", "#{last_name}%")
  else
    People.where("first LIKE ? AND LAST LIKE ?", "#{first_init}%", "#{last_name}%")
  end
end

This will result in SQL that uses the LIKE operator, which is a partial match -- the % is a SQL wildcard character, similar to * in filename matching or .* in regexp.

Sorry, my first three attempts had errors. I am checking now to see if there a way of doing wildcards more nicely...

There is no slick Ruby way. You just have to build a query. Something like this should work:

def self.find_by_abbreviated_name(name)
  if name[3].blank? && name.size >= 5 # Check if there's a middle initial
    where("first_name like ? and middle_name like ? and last_name = ?", "#{name[0]}%", "#{name[2]}%", name[4..-1])
  else # No middle initial
    where("first_name like ? and last_name = ?", "#{name[0]}%", name[2..-1])
  end
end

Explanation:

The "trick" with the name string only works if the format of the string is always the same. name[0] gives the first character of the string, name[2] gives the third character and name[4..-1] returns the fifth character to the end of the string.

I think the where clause itself is pretty straightforward. To find records based on the first character only you can use: .where('field_name like ?', "#{query}%") , where the question mark is indeed a placeholder for a replacement value.

Edit:

I updated my answer for the case where the middle initial is omitted.

This problem is an ideal candidate for using a String Ranking Algorithm !

Take a look at this implementation of the Quicksilver algorithm using Jquery / Prototype.

Basically, like others have already mentioned, this is painful to do since you cannot always account for the formats in which data is input.

I don't believe there is an active gem or ruby port, but it is fairly straightforward.

Implementing this in a rails app would mean

  1. Fetching the id and concatenated name for all people
  2. Running the algorithm on that array
  3. Fetching the top 1/3/n rows based on ids from sorted array.

I personally avoid "building" queries too often, AR is just not powerful enough as an ORM for me. But if you are going that route, you should definitely check out the Squeel gem failing which AREL is a must.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM