I have an search field for user with autocomplete, it was working but I migrated my database from mySQL to Postgresql but cannot get the concatenate working. When I type a first name or a last name is working but when my user are typing Firstname Lastname (with a space between them) it's not working anymore and cannot get it working or figure out what to do.
That's my SQL command :
#users = User.find(:all,:conditions => ['(last_name LIKE ? OR first_name LIKE ? OR (first_name || last_name) LIKE ? OR (last_name || first_name) LIKE ?) AND adult = ?', "%#{params[:term]}%", "%#{params[:term]}%", "%#{params[:term]}%", "%#{params[:term]}%", false])
My issue is here : (first_name || last_name) that will return correct value when the user type FirstNameLastName so the concat works here but when I try to add the space I cannot figure out what is wrong I tried :
(first_name ||' '|| last_name) or (first_name ||" "|| last_name)
But none of these will work I found another thread on stackoverflow but cannot get it working and I don't understand why...
Thanks,
No idea about Rails but how about
'....(first_name || \' \' || last_name)...'
Related
I have users table that has first_name and last_name. On my user index page, there is a text field for first_name and last_name search.
If I search with either first_name or last_name it works fine. But if I enter the full name in the text field then it doesn't give me any results
My User model
def fullname
first_name + last_name
end
My Query
User.where("lower(first_name) like ? or lower(last_name) like ?", "%#{params[:fullname].downcase}%", "%#{params[:fullname].downcase}%")
Concatenate the two names when searching:
User.where(
"(LOWER(first_name) || ' ' || LOWER(last_name)) LIKE ?",
"%#{params[:fullname].downcase}%"
)
I currently have a scope:
scope :named,->(query) do
where("(first_name || last_name) ~* ?", Regexp.escape(query || "a default string to prevent Regexp.escape(nil) errors"))
end
This works, except for when first_name or last_name is nil. How do I find with these columns if one of the columns is nil?
I think you can try something like this:
scope :named,->(query) do
where("first_name IS NOT NULL OR last_name IS NOT NULL AND (first_name || last_name) ~* ?", Regexp.escape(query || "a default string to prevent Regexp.escape(nil) errors"))
end
This is a basic scope to search for a name, it handles a search for 'first_name only', 'last_name only' or a search for full name.
If you split the query into an array, you can grab the first and last of the array and does not matter whether the query is one or two in length.
You could replace the split with your regex if needed
You could obviously expand on this (e.g. case insensitive, ordering), but gives the basic idea.
Also handles a nil query by defaulting to a empty string, if the strip fails.
scope :named,->(query) do
query.strip! rescue query = ""
query_words = query.split(' ')
where(["first_name LIKE ? OR last_name LIKE ?", "#{query_words.first}%", "#{query_words.last}%"])
end
Hope this helps
So, as part of a search function in a Ruby on Rails app, I've made Users searchable by first name and last name. However, when I type in their full name, it doesn't render any results. So, if a User is named John Smith, I can type in "John" or "Smith" and it will bring him up, but if I type in "John Smith" it doesn't recognize it.
I know that's because in my search code I only enabled first_name and last_name but not the User's full name. What's the proper way to concatenate the first and last names to solve this problem?
Here's the current code:
users = User.find_by_sql(['select *
from users
where first_name ilike ?
or last_name ilike ?
order by last_name limit ?', q, q, 100])
Check this code,
users = User.find_by_sql(["SELECT * FROM users WHERE (coalesce(users.first_name, '') || ' ' || coalesce(users.last_name, '') ilike '%#{p.downcase}%' )"])
What about mysql concat ?
users = User.find_by_sql(["SELECT * FROM users WHERE
CONCAT(first_name, ' ', last_name) LIKE ?
ORDER BY last_name LIMIT ?", p, 100]
)
where p could be anything John, Smith, John Smith
I'm implementing a simple search function that should check for a string in either the username, last_name and first_name. I've seen this ActiveRecord method on an old RailsCast:
http://railscasts.com/episodes/37-simple-search-form
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
But how do I make it so that it searches for the keyword in name, last_name and first name and returns the record if the one of the fields matched the term?
I'm also wondering if the code on the RailsCast is prone to SQL injections?
Thanks a lot!
I assumed your model name is Model - just replace it with your real model name when you do the actual query:
Model.where("name LIKE ? OR last_name LIKE ? OR first_name LIKE ?", "%#{search}%","%#{search}%","%#{search}%")
About your worries about SQL injections - both of code snippets are immune to SQL injections. As long as you do not directly embed strings into your WHERE clause you are fine. An example for injection-prone code would be:
Model.where("name LIKE '#{params[:name]}'")
Although the selected answer will work, I noticed that it breaks if you try to type a search "Raul Riera" because it will fail on both cases, because Raul Riera is not either my first name or my last name.. is my first and last name... I solved it by doing
Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#{search.downcase}%")
With Arel, you can avoid writing the SQL manually with something like this:
Model.where(
%i(name first_name last_name)
.map { |field| Model.arel_table[field].matches("%#{query}%")}
.inject(:or)
)
This would be particularly useful if the list of fields to match against was dynamic.
A more generic solution for searching in all fields of the model would be like this
def search_in_all_fields model, text
model.where(
model.column_names
.map {|field| "#{field} like '%#{text}%'" }
.join(" or ")
)
end
Or better as a scope in the model itself
class Model < ActiveRecord::Base
scope :search_in_all_fields, ->(text){
where(
column_names
.map {|field| "#{field} like '%#{text}%'" }
.join(" or ")
)
}
end
You would just need to call it like this
Model.search_in_all_fields "test"
Before you start.., no, sql injection would probably not work here but still better and shorter
class Model < ActiveRecord::Base
scope :search_all_fields, ->(text){
where("#{column_names.join(' || ')} like ?", "%#{text}%")
}
end
The best way to do this is:
Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#{query}%")
I'm following ryan's Simple Search Form tutorial here:
http://railscasts.com/episodes/37-simple-search-form
I have the following line in my Users Model:
find(:all, :conditions => ['fname LIKE ?', "%#{search}%"])
But what I'd like to do is search across a combine 2 columns,: fname & lname
As users are searching my full names:
Example, James Brown
fname = James
lname = Brown
Is there a way to do this in Rails safely that will work across DBs like SQLite, MySQL or Postgres (heroku uses)?
Thanks!
It may not be pretty, but I use this in my Person model:
scope :by_full_name lambda {|q|
where("first_name LIKE ? or last_name LIKE ? or concat(last_name, ', ', first_name) LIKE ?", "%#{q}%", "%#{q}%" , "%#{q}%")
}
See one of my other posts for an bit extra that will let the search query be optional.
This ended up working extremely well... Not sure about performance though. Can Indexes Help This?
:conditions => ['fname || lname LIKE ?', "%#{search}%"]