Where clause on model associations - ruby-on-rails

I have below where clause:
users.joins(:role).where("roles like :search OR email like :search OR first_name like :search OR last_name like :search",
search: "%#{params[:sSearch]}%")
I want to be able to query roles table name column.
This doesn't seem to work.
Is there a good way to achieve this containing all other conditions in the above?

try this
users.joins(:role).where("roles.name like :search OR email like :search OR first_name like :search OR last_name like :search",
search: "%#{params[:sSearch]}%")

Related

how to use LIKE in search in rails

def self.search_by(search_term)
where("LOWER (course_name) LIKE :search", search_term: "%#{search_term}%")
end
this is my code, it seems LIKE query doesn't work at all
Your code where("LOWER (course_name) LIKE :search", search_term: "%#{search_term}%") isn't working because it's expecting an argument search but you're passing search_term. So, modify it to:
where("LOWER (course_name) LIKE :search", search: "%#{search_term}%")
now you're providing the same variable which it's expecting to get in "LOWER (course_name) LIKE :search".
#venues = Venue.where('name LIKE ?', "%#{#query}%")
scope :search_by, -> (search_term){ where("LOWER(course_name) LIKE ?", "%#{search_term.to_downcase}%")}
OR
def self.search_by(search_term)
where("LOWER(course_name) LIKE ?", "%#{search_term.to_downcase}%")
end
update your query to
where("LOWER (course_name) LIKE :search_term", search_term: "%#{search_term}%")
change the :search keyword with :search_term , you used alias :search in query but specify :search_term to assign search value.
The keyword ILIKE can be used instead of LIKE to match case-insensitive strings, so you don't have to use LOWER.
Also, the reason your query is not working is that you have to change the :search_term alias with :search.
def self.search_by(search_term)
where("course_name ILIKE :search", search: "%#{search_term}%")
end

Search multiple columns - Rails

I am currently writing a search method for my rails applications, and at the moment it works fine. I have the following in my game.rb:
def self.search(search)
if search
find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#{search}%", "#{search}", "#{search}"])
else
find(:all)
end
end
Now that searches fine, but my problem is that if there is a record in game_name that has the word 'playstation' in it, it will finish the search there. It only returns that record, rather than all games that have 'playstation' stored in console. Now I understand this is because I have 'OR' in my conditions, but I don't know an alternative. 'AND' requires all the conditions to match or none return at all. What is an alternative I can use to AND and OR? Help would be much appreciated.
If there is a solution that has separate search boxes and entries, then that would be fine, I don't necessarily require the search to find it all based on one search form.
If I understand your question correctly, your SQL looks good to me for what you are trying to do. An OR clause will return all records that match in column1, column2, or column3. It doesn't stop at the first match. I do see an issue with your parameters in that the first you are using LIKE with % but in the second two you aren't, maybe that is where your issue is coming from.
Should this be your find (% around second and third search)?
find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%"])
or better use DRY version (above will not work for Rails 4.2+):
Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: "%#{search}%")
What if you have 15 columns to search then you will repeat key 15 times. Instead of repeating key 15 times in query you can write like this:
key = "%#{search}%"
#items = Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: key).order(:name)
It will give you same result.
Thanks
I think this is a little bit of a cleaner solution. This allows you to add/remove columns more easily.
key = "%#{search}%"
columns = %w{game_name genre console}
#items = Item.where(
columns
.map {|c| "#{c} like :search" }
.join(' OR '),
search: key
)
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
I think this is a more efficient solution if you want to search an array of columns as I do.
First and most importantly you can add a private function to your model that creates a query template:
def self.multiple_columns_like_query(array)
array.reduce('') { |memo, x| #
unless memo == '' #
memo += ' or ' # This is the
end #
memo += "#{x} like :q" # core part
} #
end
Than you can use the function in your search function:
def self.search(query)
if fields = self.searched_fields && query
where multiple_like_query(fields), q: "%#{query}%"
end
end
Here you should also define self.searched_fields as an array of field names.

Search with multiple columns in Rails

While using the command:
#items = Item.find(:all,:order => 'name', :conditions => ["name LIKE ?", "%#{params[:key]}%"])
This works perfectly fine, but the search is only based on just a column. How do i make it search other columns, like description, category?
I am assuming you are using Rails 2, since you are using ActiveRecord 2 style syntax. You can just add the other columns as additional conditions, like this:
key = "%#{params[:key]}%"
#items = Item.find(:all, :conditions => [
'name LIKE ? OR description LIKE ? OR category LIKE ?',
key, key, key
], :order => 'name')
For reference, here's how you would do it in Rails 3:
key = "%#{params[:key]}%"
#items = Item.where('name LIKE ? OR description LIKE ? OR category LIKE ?', key, key, key).order(:name)
What if you have 15 columns to search then you will repeat key 15 times. Instead of repeating key 15 times in query you can write like this:
key = "%#{params[:key]}%"
#items = Item.where('name LIKE :search OR description LIKE :search OR category LIKE :search', search: key).order(:name)
It will give you same result.
Thanks

Rails 3: Trying to understand join query

I have a User class and a GroupUser class. I'm trying to do a search by name of the users. I tried following what I read on the joins, but I have something wrong. Also I need to change my name portion of the query to a like instead of an equals
Here is the query I had initially built.
#users = GroupUser.joins(:users).where(:group_id => params[:group_id]).where(:users => {:name => params[:q]})
Try this:
#users = User.where("name ilike ? and id in (select distinct user_id from groups_users where group_id = ?)", "%#{params[:q]}%", params[:group_id])

How to do a LIKE query in Arel and Rails?

I want to do something like:
SELECT * FROM USER WHERE NAME LIKE '%Smith%';
My attempt in Arel:
# params[:query] = 'Smith'
User.where("name like '%?%'", params[:query]).to_sql
However, this becomes:
SELECT * FROM USER WHERE NAME LIKE '%'Smith'%';
Arel wraps the query string 'Smith' correctly, but because this is a LIKE statement it doesnt work.
How does one do a LIKE query in Arel?
P.S. Bonus--I am actually trying to scan two fields on the table, both name and description, to see if there are any matches to the query. How would that work?
This is how you perform a like query in arel:
users = User.arel_table
User.where(users[:name].matches("%#{user_name}%"))
PS:
users = User.arel_table
query_string = "%#{params[query]}%"
param_matches_string = ->(param){
users[param].matches(query_string)
}
User.where(param_matches_string.(:name)\
.or(param_matches_string.(:description)))
Try
User.where("name like ?", "%#{params[:query]}%").to_sql
PS.
q = "%#{params[:query]}%"
User.where("name like ? or description like ?", q, q).to_sql
Aaand it's been a long time but #cgg5207 added a modification (mostly useful if you're going to search long-named or multiple long-named parameters or you're too lazy to type)
q = "%#{params[:query]}%"
User.where("name like :q or description like :q", :q => q).to_sql
or
User.where("name like :q or description like :q", :q => "%#{params[:query]}%").to_sql
Reuben Mallaby's answer can be shortened further to use parameter bindings:
User.where("name like :kw or description like :kw", :kw=>"%#{params[:query]}%").to_sql
Don't forget escape user input.
You can use ActiveRecord::Base.sanitize_sql_like(w)
query = "%#{ActiveRecord::Base.sanitize_sql_like(params[:query])}%"
matcher = User.arel_table[:name].matches(query)
User.where(matcher)
You can simplify in models/user.rb
def self.name_like(word)
where(arel_table[:name].matches("%#{sanitize_sql_like(word)}%"))
end

Resources