Rails Simple Search - ruby-on-rails

I have a basic search that is not working and I dont understand why.
In my model I have this
def self.search(search)
if search
search_condition = "%" + search + "%"
find(:all, :conditions => ['jobTitle LIKE ? OR jobDescription LIKE ?', search_condition, search_condition])
end
end
A parameter does get passed to it then an error comes up:
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: "all" LINE 1: ...ngs".* FROM "postings" WHERE "postings"."id" IN ('all', '--... ^ : SELECT "postings".* FROM "postings" WHERE "postings"."id" IN ('all', '--- :conditions: - jobTitle LIKE ? OR jobDescription LIKE ? - "%drew%" - "%drew%" ')
Am I doing something wrong?

You are using outdated syntax for find. Use where instead:
def self.search(search)
if search
search_condition = "%" + search + "%"
where(['jobTitle LIKE ? OR jobDescription LIKE ?', search_condition, search_condition])
end
end

Related

How to use like clause query in rails?

I wanted to get a json format of the data when searching for the keyword so I use LIKE clause and query like this
"select * from employees where fname like ? or mname like ? or lname like ? or username like ? or id like ?", str, str, str, str, str
but I want to code it using rails. I have this code in my controller
def showemployees
str = params[:str]
render json: #employee = Employee.where(Employee.employees[:fname].matches("%#{str}%")) or
(Employee.employees[:mname].matches("%#{str}%")) or
(Employee.employees[:lname].matches("%#{str}%")) or
(Employee.employees[:id].matches("%#{str}%"))
end
and this code in my config/routes.rb
get 'employees/showemployees'
root :to => 'employees#new'
resources :employees
post 'employees/update_info'
when i type this, http://localhost:3000/employees/showemployees?str=samplename, a json format of the record should appear yet I got this error message
undefined method `employees' for #<Class:0x8e38900>
app/controllers/employees_controller.rb:6:in `showemployees'
where line 6 has this code
render json: #employee = Employee.where(Employee.employees[:fname].matches("%#{str}%")) or
You can chain where queries, but this AND each where query results
Employee.where('fname LIKE ?', "%#{str}%").where('lname LIKE ?', "%#{str}%").where('mname LIKE ?', "%#{str}%").where('username LIKE ?', "%#{str}%").where('id LIKE ?', "%#{str}%")
or to use OR clause
Employee.where('fname LIKE ? OR lname LIKE ? OR mname', "%#{str}%", "%#{str}%", "%#{str}%")

Search every field or attribute in model Rails

I have a simple model called Company with atributes such as Name, contact email, address, etc. I've created a search form where a user can find the company by searching for any attribute i.e., city, name of business, etc.
I'm new to Rails but I've figured out how to get it working like so in my controller.
if(params[:searchstring].present?)
logger.debug "*** Running search --> "
term = params[:searchstring]
#companies = Company.where('name LIKE ? OR name LIKE ? OR contactemail LIKE ? OR city LIKE ?' , "%#{term}%", "%#{term}%", "%#{term}%","%#{term}%" ).paginate(page: params[:page]).order('id DESC')
else
logger.debug "*** Running search --> get em all "
#companies = Company.all.paginate(page: params[:page], per_page: 5).order('id DESC')
end
end
This works fine but I'm guessing there is a much simplier way. I'd prefer not to modify the query every time I add an attribute. Any ideas on how to improve this?
You could go with something like this (It is just an example, might be a better way, but it is fonctionnal)
# company.rb
def self.search_all_properties term
query = ''
properties = Company.column_names
properties.each_with_index do |prop, index|
if index < properties.count - 1
query = query + prop + ' LIKE :term OR '
else
query = query + prop + ' LIKE :term'
end
end
term = "%" + term + "%"
Company.where(query, :term => term)
end
and use it like this
Company.search_all_properties term

Optional Rails Params in Controller Query

I have a question in regards to Rails params. I currently have only one filter on one of my views that allows users to filter data by a date range. I am adding two more filters to that view so that users can filter by code and country. However, I want those filters to be optional.
My current query looks something like this:
#data = Games
.where("date BETWEEN ? AND ?", *date_range_array)
.includes(:synced_country)
.order(sort_column + " " + sort_direction)
.page(params[:page])
The params for code and country will be something like, params[:code] and params[:country]. I would like to put them in the query like:
#data = Games
.where("date BETWEEN ? AND ?", *date_range_array)
.where("unique_code in ?" params[:code])
.where("country in ?" params[:country])
.includes(:synced_country)
.order(sort_column + " " + sort_direction)
.page(params[:page])
The issue I am having is that if the user does not input anything for params[:code] and params[:country] I get an error because they are nil. Any idea on how to handle this kind of situation?
I would build it incrementally:
#data = Games.where("date BETWEEN ? AND ?", *date_range_array)
#data = #data.where("unique_code in ?", params[:code]) if params[:code]
#data = #data.where("country in ?", params[:country]) if params[:country]
#data = #data.includes(:synced_country)
.order(sort_column + " " + sort_direction)
.page(params[:page])
Note that you are missing two commas right before params[:code] and params[:country] which I've fixed in the above code.
#data = Games.where("date BETWEEN ? AND ?", *date_range_array).scoped
#data = #data.where("unique_code in ?" params[:code]).scoped if params[:code].present?
#data = #data.where("country in ?" params[:country]).scoped if params[:coutry].present?
#data = #data.includes(:synced_country)
.order(sort_column + " " + sort_direction)
.page(params[:page])
Anyway, I would move that complex query to a named scope or something inside the Game Model.
EDIT: added the "scoped" method, i'm not sure if needed, try it without .scoped if you want
I usually use the same method with Agis.
But sometimes I trend to use scope(as arieljuod said):
class Games
scope :in_contry, lambda{|contry| where("contry in ?", contry) if contry.present?}
scope :in_code, lambda{|code| where("unique_code in ?", code) if code.present?}
//other codes
end
//call lambdas as follows:
#data = Games.where("date BETWEEN ? AND ?", *date_range_array)
.in_code(params[:code])
.in_contry(params[:country])
.includes(:synced_country)
.order(sort_column + " " + sort_direction)
.page(params[:page])

Search through sentences

I have a rails app and have decided to have a search. I have a search textfield and the controller takes care of everything. In my search method
def self.search(search)
if search
str = []
search.split.each do |s|
a = find(:all, :conditions => ['title or content LIKE ?', "%#{s}%" ])
str = (str + a).uniq
end
else
find(:all)
end
end
I want to be able to handle multiple word searches. If you remove the each...loop it works fine with 1 word searches.
Anyways, I would like to find the related posts for each word that is searched and return a combination of that.
Ex. If someone searches "Greatest Player" it will return all instances of posts that have the title or content "Greatest" and any that have the title or content "Player"
You most likely should be looking at full text searching:
Full Text Searching with Rails
http://en.wikipedia.org/wiki/Full_text_search
Shouldn't it be
a = find(:all, :conditions => ['title or content LIKE ?', "%#{s}%" ])
All you needed was to change the find statement to Mischa's code and add a return statement
Working Code:
def self.search(search)
if search
str = []
search.split.each do |s|
a = where(title LIKE ? or content LIKE ?', "%#{s}%", "%#{s}%")
str = (str + a).uniq
end
return str
else
find(:all)
end
end

How can I convert that to MetaWhere or Arel?

Consider a City Model having:
def self.search(field, search)
if search
where("#{field} LIKE ?", "%#{search}%")
else
scoped
end
end
How can I use Arel or Metawhere in that situation knowing that field is a String can have anything like:
"name"
"residents.name"
"state.name"
I want to do something like that (will not work):
def self.search(field, search)
if search
where(field =~ "%#{search}%")
else
scoped
end
end
So, what are your thoughts?
The real question is, how can I convert that:
"residents.name LIKE '#{value}%'"
To that:
:residents => { :name =~ "#{value}%" }
You should be able to use Arel like this.
def self.search(field, search)
if search
if field =~ /\./ # table and field
table, field = field.split('.')
arel_join = table.singularize.camelize.constantize.arel_table
joins(table.to_sym).where(arel_join[field].matches("%#{search}%"))
else
where(Resource.arel_table[field].matches("%#{search}%"))
end
else
scoped
end
end
There's a Railscast that does a good job of explaining the basics of using Arel in Rails 3.

Resources