Postgres full text not matching partial words in Rails 3? - ruby-on-rails-3

I just moved from MySQL to Postgres 9.0.3. I have a brand new app with a little data (game data).
Anyway, I can't seem to get partial words to search. Here is my search method:
def self.search(query)
conditions = <<-EOS
to_tsvector('english', title) ## plainto_tsquery('english', ?)
EOS
find(:all, :conditions => [conditions, query])
end
I'm sure I need a wildcard in there but I'm just learning Postgres.
When I search for Shinobi I get the correct results:
Alex Kidd in Shinobi World - Sega Master System
Shinobi - Sega Master System
Shinobi - Nintendo Entertainment System
The Cyber Shinobi: Shinobi Part 2 - Sega Master System
But when I search for Shin I get nothing?
Thanks for any clues.

I think that to allow prefix matching you need to use to_tsquery instead of plainto_tsquery
that says http://www.postgresql.org/docs/current/static/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
so your code could be something like
def self.search(query)
conditions = <<-EOS
to_tsvector('english', title) ## to_tsquery('english', ?)
EOS
find(:all, :conditions => [conditions, query + ':*'])
end

You can also use a regular expression search as shown below.
find( :all, :conditions => [ 'name ~* ?', "SEARCH TERM" ] )

Append a * to your query string.
Search for Shin*.
def self.search(query)
conditions = <<-EOS
to_tsvector('english', title) ## plainto_tsquery('english', ?)
EOS
find(:all, :conditions => [conditions, query.concat("*")])
end

Use the prefix:
pg_search_scope :search, against: [:name, :email],
using: {tsearch: {prefix: true}}

Related

how do i get a rails WHERE query to be more specific? "Like" works, = doesn't

I am very new to Rails and am trying to create a search field to query my database. When I use the WHERE method and use "like", it works, but it's far too broad. If a person's last name is Smith, and I search for "i", it will return Smith as that string contains an "i". How can I make it more specific? I've searched around, read the docs and thought the following should work, but it doesn't return records.
this works
def self.search(query)
where("last_name like ? OR email like ?", "%#{query}%", "%#{query}%")
end
this does not
def self.search(query)
where("last_name = ? OR email = ?", "%#{query}%", "%#{query}%")
end
You're going to want to look more into SQL, as this is very specifically an SQL question. The % operator in SQL returns a fuzzy match. You want a strict match. So
def self.search(query)
where("last_name = ? OR email = ?", query, query)
end
or more succinctly:
scope :search, ->(query) { where('last_name = :query OR email = :query', query: query) }

Rails 4 LIKE query - ActiveRecord adds quotes

I am trying to do a like query like so
def self.search(search, page = 1 )
paginate :per_page => 5, :page => page,
:conditions => ["name LIKE '%?%' OR postal_code like '%?%'", search, search], order => 'name'
end
But when it is run something is adding quotes which causes the sql statement to come out like so
SELECT COUNT(*)
FROM "schools"
WHERE (name LIKE '%'havard'%' OR postal_code like '%'havard'%')):
So you can see my problem.
I am using Rails 4 and Postgres 9 both of which I have never used so not sure if its and an activerecord thing or possibly a postgres thing.
How can I set this up so I have like '%my_search%' in the end query?
Your placeholder is replaced by a string and you're not handling it right.
Replace
"name LIKE '%?%' OR postal_code LIKE '%?%'", search, search
with
"name LIKE ? OR postal_code LIKE ?", "%#{search}%", "%#{search}%"
Instead of using the conditions syntax from Rails 2, use Rails 4's where method instead:
def self.search(search, page = 1 )
wildcard_search = "%#{search}%"
where("name ILIKE :search OR postal_code LIKE :search", search: wildcard_search)
.page(page)
.per_page(5)
end
NOTE: the above uses parameter syntax instead of ? placeholder: these both should generate the same sql.
def self.search(search, page = 1 )
wildcard_search = "%#{search}%"
where("name ILIKE ? OR postal_code LIKE ?", wildcard_search, wildcard_search)
.page(page)
.per_page(5)
end
NOTE: using ILIKE for the name - postgres case insensitive version of LIKE
While string interpolation will work, as your question specifies rails 4, you could be using Arel for this and keeping your app database agnostic.
def self.search(query, page=1)
query = "%#{query}%"
name_match = arel_table[:name].matches(query)
postal_match = arel_table[:postal_code].matches(query)
where(name_match.or(postal_match)).page(page).per_page(5)
end
ActiveRecord is clever enough to know that the parameter referred to by the ? is a string, and so it encloses it in single quotes. You could as one post suggests use Ruby string interpolation to pad the string with the required % symbols. However, this might expose you to SQL-injection (which is bad). I would suggest you use the SQL CONCAT() function to prepare the string like so:
"name LIKE CONCAT('%',?,'%') OR postal_code LIKE CONCAT('%',?,'%')", search, search)
If someone is using column names like "key" or "value", then you still see the same error that your mysql query syntax is bad. This should fix:
.where("`key` LIKE ?", "%#{key}%")
Try
def self.search(search, page = 1 )
paginate :per_page => 5, :page => page,
:conditions => ["name LIKE ? OR postal_code like ?", "%#{search}%","%#{search}%"], order => 'name'
end
See the docs on AREL conditions for more info.
.find(:all, where: "value LIKE product_%", params: { limit: 20, page: 1 })

Rails Active Record Search - Name includes a word

Im trying to pull all records from a Project model that includes in the project_name the word 'Fox'. I can do an active record search and return specific project_names, like 'Brown Fox':
#projects = Project.where("project_name like ?", "Brown Fox")
But if I want to return all the names that INCLUDE 'Fox', this does not work unless the complete project name is 'Fox':
#projects = Project.where("project_name like ?", "Fox")
How do I do a search that returns all the objects with the word 'Fox' in the name?
Try using:
variable = "Fox"
Project.where("project_name like ?", "%#{variable}%")
You can use the SQL % operator:
#projects = Project.where("project_name like ?", "%Fox%")
Note that if you want your query to return results ignoring the word case, you can use PostgreSQL ilike instead of like.
Did you try ransack ?
With ransack you can do something like
#projects = Project.search(:project_name_cont => "Fox")
If you think it is too much for what you need. you can use the % operator as MurifoX said
Here's a version that will allow you to handle any number of input words and to search for all of them within a name. I was looking for this answer and didn't find the more complicated case, so here it is:
def self.search(pattern)
if pattern.blank? # blank? covers both nil and empty string
all
else
search_functions = []
search_terms = pattern.split(' ').map{|word| "%#{word.downcase}%"}
search_terms.length.times do |i|
search_functions << 'LOWER(project_name) LIKE ?'
end
like_patterns = search_functions.join(' and ')
where("#{like_patterns}", *search_terms)
end
end

Rails 3 joining multiple where condition

Would like to build rails active record query with multiple optional where conditions.
Example:
I have a patient search form that able to search by id, name and email address. The pseudo code would be as below:
where_sql = ""
where_sql = {'name = ?", params[:name]} if params[:name]
where_sql = {'id = ?", params[:id]} if params[:id]
where_sql = {'email = ?", params[:email]} if params[:email]
Patient.where(where_sql)
How do I build following queries without worrying about sql injection.
If you use questionmark "?" placeholders or hashes ActiveRecord automatically escapes the values for you. See injection countermeasures in rails guides http://guides.rubyonrails.org/security.html#sql-injection
This might be a nice use case for the ransack gem (MetaWhere rewrite) https://github.com/ernie/ransack
If you are using only equal conditions, you can do it like:
conditions = {}
conditions[:name] = params[:name] if params[:name]
conditions[:id] = params[:id] if params[:id]
conditions[:email] = params[:email] if params[:email]
Patient.where(conditions)
Also, take a look to a great searchlogic gem.

Refactoring SQL

I must connect from my Rails app to a remote database on a Java application.
I have a query like this:
find_by_sql("select c_templateid, c_templateinfoid, c_startdate, c_enddate, c_active,
campaign, shortcode, prefix, c_descriptivename, c_description, c_templatename
from (active_services aser join activity a on aser.c_primaryprefixid =
a.c_primaryprefixid ) join matrix_templateinfo using(c_templateinfoid)
where campaign is not null)")
I need to refactor it to the AR#find() method, because I want later add complex :conditions on it. I dont want convert them into string to append then later to the find_by_sql method.
find(:all,
:select => "c_templateid, c_templateinfoid, c_startdate, c_enddate, c_active,
campaign, shortcode, prefix, c_descriptivename, c_description, c_templatename",
# :joins => WHAT I SHOULD DO HERE ?
:conditions => "campaign is not null"
)
You can also specify complex joins in :joins
:joins => "matrix_templateinfo ON <conditions go here> AND campaing IS NOT NULL"
but you should really start padronizing your field names if you're using rails :]