For this task, I needed to select users if they practiced certain type of law according to the search terms. As such, there are Users who have many Practices through Practice_Users, and Practices have many Users though Practice_Users. I wanted to select Users with Practices if search terms matched the Practices. However, there are several stop words to avoid: for example, if two records in the database list 'Family law' and 'Family', and I want to search for 'family', then both records should be returned.
My initial solution was the following:
scope :by_practice, -> (pract) {joins(:practice_users).where("practice_users.practice_id IN (SELECT id FROM practices where name IN (?))", pract )}However, this solution would work if only the search terms matched the database records exactly. Thus, searching for 'family' would exclude 'Family law'.
The second solution was the following:
scope :by_practice, -> (pract) {joins(:practice_users).where("practice_users.practice_id IN (SELECT id FROM practices WHERE #{pract})")}
pract = practices.map { |e| "name iLIKE '%#{e}%'"}.join(" or ")However, this solution is vulnerable to SQL injection due to the use of #{} in sql string i.e., #{pract}.
The third and final solution was sort of a combination of the first two: it used ? substitution in Rails and a regex expression in Postgres:
scope :by_practice, -> (pract) {joins(:practice_users).where("practice_users.practice_id IN (SELECT id FROM practices WHERE name ~* ?)", pract)}
pract = practices.map {|e| "#{e}"}.join('|')
No comments :
Post a Comment