Searchkick: Searching multiple specific fields in the same query - ruby-on-rails

i'm trying to make an advanced search in my rails app but i'm having some problems with empty params
class Product< ActiveRecord::Base
searchkick
when i fill the search and size fields everyting works, but if i leave size field blank nothing show up in the results...
probably i'm doing something stupid
i made it work with a bunch of IFs:
def index
if params[:search].present?
if params[:size].present?
#products = Product.search params[:search], where: {size: params[:size]}
else
#products = Product.search params[:search]
end
else
if params[:size].present?
#products = Product.search "*", where: {size: params[:size]}
else
#products = Product.search "*"
end
end
but probably thats not the best approuch, having in mind that i will search in at least 5 other fields...
Search, Size, Brand, Color, Store.state, Price, Rating etc...
sorry for my english, i hope you guys understand my question and get able to help me..

My be smth:
...
search_condition = params[:search] || '*'
where_conditions = params.slice(:size, :brand, :color, ...)
#products = if where_conditions.any?
Product.search search_condition, where: where_conditions
else
Product.search search_condition
end

Found a solution where
Setting up Facets in Elasticsearch with Searchkick gem in Rails 4.1
query = params[:query].presence || "*"
conditions = {}
conditions[:state] = params[:state] if params[:state].present?
conditions[:city] = params[:city] if params[:city].present?
movies = Movie.search query, where: conditions

Related

Using where search clause after select

I'm new to rails and I'm adding some updates to already existing app. I need to add filtering by search word and I'm trying to use where with ILIKE to do that but due to the original code is written. the original code uses Model.select to get the records and when i try to chain where with the ILIKE clause to that it still returns the whole array not filtered.
date_format = get_js_date_format_by_id(#account.date_format_id)
sort_format = "#{params[:sort_item] || "date"} #{params[:sort_order] || "asc"}"
#expenses = Expense.select("expenses.*, to_char(expenses.date, '#{date_format}') as formatted_date,
to_char(
CASE
WHEN expense_categories.is_calculated = true then expenses.amount * expense_categories.unit_cost
ELSE expenses.amount
END, 'FM999999990.00') as total,
CASE
WHEN expense_categories.is_calculated = true then expense_categories.unit_name
ELSE null
END as unit_name,
'' as images_list,
users.name as user_name, expense_categories.name as category_name, projects.name as project_name, clients.name as client_name")
.joins(:user, :project, :expense_category, :client)
if params[:query]
#expenses.includes(:user).where('users.name ILIKE :query', { query: "%#{params[:query]}%"}).references(:users)
end
#expenses.where(conditions)
.order(sort_format)
if params[:page]
#expenses = #expenses.page(params[:page]).per(params[:per_page])
end
#expenses
I'm adding the filtering part starting at if params[:query] the rest is the original code. any help would be appreciated to pin pointing the problem.
thanks!
The problem is that you don't modify the current #expenses scope with:
if params[:query]
#expenses.includes(:user).where('users.name ILIKE :query', { query: "%#{params[:query]}%"}).references(:users)
end
This line returns the new scope you want, but you are not saving it anywhere. Following code should work:
if params[:query]
#expenses = #expenses.includes(:user).where('users.name ILIKE :query', { query: "%#{params[:query]}%"}).references(:users)
end
Note: same thing applies for the sorting under the params[:query] condition.

Multiple where clauses in rails searchkick

I have a very basic question about searchkick. What if you want you join multiple where statements in searchkick query using if statements. Much like query-builder
#product = Product.all
unless request.end_date.nil?
#product = #product.search, where('created_at <= ?', request.end_date)
end
unless request.max_price.nil?
#product = #product.search, where('price <= ?', request.max_price)
end
#product
The above code works fine if request has either end date or max_price. If it has both, it throws an error. Is there a way to construct or concatenate the two where statements. I cannot do
Product.search '*', where('created_at <= ?', request.end_date), where('price <= ?', request.max_price)
because if statement is important.
You should check docs of Searchkick, it has Or filter: https://github.com/ankane/searchkick
where: {
expires_at: {gt: Time.now}, # lt, gte, lte also available
or: [
[{in_stock: true}, {backordered: true}]
]
}
For your case, you can deal with it as below:
conditions[:or] = [[]]
unless request.end_date.nil?
conditions[:or][0] += [{created_at: {lt: request.end_date}}]
end
unless request.max_price.nil?
conditions[:or][0] += [{price: {lt: request.max_price}}]
end
Product.search '*', where: conditions

Rails handle multiple Params in search query

I have the following model and I want to pass multiple params in "with_query", don't know how to achieve it. currently you can see it takes only "query" param. how can I filter it with country and job_type. any help would be really appreciated.
search Model
def self.search(query, country, job_type, page = 1)
results = []
Refinery.searchable_models.each do |model|
results << model.limit(RESULTS_LIMIT).with_query(query)
end if query.present?
results.flatten[0..(RESULTS_LIMIT - 1)]
end
Controller
def show
#results = Refinery::SearchEngine.search(params[:query], params[:country], params[:job_type], params[:page])
present(#page = Refinery::Page.find_by_link_url("/search"))
end
I would try changing the line that builds your results in the search model to:
results << model.limit(RESULTS_LIMIT).with_query(query).where(country: country, job_type: job_type)

Setting default search parameter on Ransack for rails

I've been wracking my brain over this but can't get it. I feel like the answer is probably obvious.
What I'm trying to do is the following:
I have an index controller which lists a series of Jobs which I can search using Ransack. Each job has a completion date which either has a date in it or is null (unfinished). Currently, the search itself works great. I would like to make it so that the index page loads up showing only the unfinished work, but I also want it to work so that when someone does run a search, returns results for both finished and unfinished work.
Any help would be greatly appreciated. In the code below, :actual is the name of the field with the completion date. I also was looking around the web and thought that maybe something like the DEFAULT_SEARCH_PARAMETER={} that I have in the Job model might work but I couldn't seem to get it to.
Here is the code:
class Job < ActiveRecord::Base
DEFAULT_SEARCH_PARAMETER ={}
attr_accessible :items_attributes, :actual
end
def index
#search = Job.search(params[:q] || Job::DEFAULT_SEARCH_PARAMETER)
#search.build_condition
#results = #search.result
#job = #results.paginate(:per_page => 10, :page => params[:page])
end
Late to the party, but thought I'd suggest an alternate approach in case someone else comes across this.
The answer above works, but its disadvantage is that the default is not added to Ransack's search object, so - if you are using a search form - the default selection is not shown in the form.
The following approach adds the default to the search object and therefore will appear in your search form.
def index
#search = Job.search(params[:q])
#search.status_cont = 'Open' unless params[:q] #or whatever, must use Ransack's predicates here
#results = #search.result
#job = #results.paginate(:per_page => 10, :page => params[:page])
end
I think you could just apply your own filter when the search parameters don't exist:
def index
#search = Job.search(params[:q])
#results = #search.result
#results = #results.where(:your_date => nil) unless params[:q]
#job = #results.paginate(:per_page => 10, :page => params[:page])
end
Many years later I found myself with this exact problem so I thought I'd chime in with a solution I'm using. Set default search params in the controller and reverse merge them into params[:q]:
def index
default_search_params = {
status_cont: "open"
}
#search = Job.search((params[:q] || {}).reverse_merge(default_search_params))
...
end
So by default, you want the page to load with records where actual is nil. And later when the user searches you want to go back to how your search was working before.
Give this a try.
def index
#search = Job.search(params[:q] || Job::DEFAULT_SEARCH_PARAMETER)
#search.build_condition
#results = #search.result
if #results.nil?
#results=Job.find(:all, :conditions => ["actual = NULL"] )
end
#job = #results.paginate(:per_page => 10, :page => params[:page])
end

Optional mix of filter parameters in a search the Rails way

I've got a simple list page with a couple of search filters status which is a simple enumeration and a test query which I want to compare against both the title and description field of my model.
In my controller, I want to do something like this:
def index
conditions = {}
conditions[:status] = params[:status] if params[:status] and !params[:status].empty?
conditions[???] = ["(descr = ? or title = ?)", params[:q], params[:q]] if params[:q] and !params[:q].empty?
#items = Item.find(:all, :conditions => conditions)
end
Unfortunately, it doesn't look like I can mix the two types of conditions (the hash and the paramatized version). Is there a "Rails Way" of doing this or do I simply have to do something awful like this:
has_status = params[:status] and !params[:status].empty?
has_text = params[:q] and !params[:q].empty?
if has_status and !has_text
# build paramatized condition with just the status
elsif has_text and !has_status
# build paramatized condition with just the text query
elsif has_text and has_status
# build paramatized condition with both
else
# build paramatized condition with neither
end
I'm migrating from Hibernate and Criteria so forgive me if I'm not thinking of this correctly...
Environment: Rails 2.3.4
You can mix hash and array conditions using scopes:
hash_conditions = {}
# build hash_conditions
items_scope = Item.scoped(:conditions => hash_conditions)
unless params[:q].blank?
items_scope = items_scope.scoped(:conditions => ["(descr = ? or title = ?)", params[:q], params[:q]])
end
...
items = items_scope.all
So you can mix and match any types of conditions, and the query will be executed only when you do items_scope.all
a=[],b=[]
unless params[:status].blank?
a << "status = ?"
b << params[:status]
end
unless params[:q].blank?
a << "(descr = ? or title = ?)"
b << params[:q] << params[:q]
end
#items = Item.all( :conditions => [a.join(" AND "), b] )
A better search on my part turned up something called "named scopes" which looks like is exactly what I'm looking for. I'm about to see if it will work with the will_paginate gem....
Reference:
http://edgerails.info/articles/what-s-new-in-edge-rails/2010/02/23/the-skinny-on-scopes-formerly-named-scope/

Resources