How to combining two search parameters in Rails - ruby-on-rails

I am just getting into Rails and want to preform a simple search FROM destination TO destination. I have the basic search functionality working and connected to the database but when I choose FROM and TWO the output is combined and I get all transports FROM the specific text and all transports TO the specific text. I want to filter them and only have the ones that go FROM TO.
Here is what I have so far.
class Transport < ApplicationRecord
def self.searchfrom(searchfrom)
where("strtloc LIKE ?", "%#{searchfrom}%")
end
def self.searchto(searchto)
where("endloc LIKE ?", "%#{searchto}%")
end
end
I basically want to add AND in between the two parameters but I am stuck.
This is my transports_controller.rb
if params[:searchfrom]
#transports = Transport.searchfrom(params[:searchfrom])
else
#transports = Transport.all
end
if params[:searchto]
#transports = Transport.searchto(params[:searchto])
else
#transports = Transport.all
end
I also want the ability to only select FROM. So I cant really do a simple AND statement. But one at a time.
Any help apreciated!

Please check this answer:
Ruby on Rails: Search Form - multiple search fields
You should find this is related to you problem.

You can do either of the following:
#transports = Transport.where("strtloc LIKE ? AND endloc LIKE ?", "#{params[:searchfrom]}%", "#{params[:searchto]}%")
It'll do an AND operations between the two parameters.
or
#transports = Transport.where("strtloc LIKE ?", "#{params[:searchfrom]}%")
# first search for start locations
#transports = #transports.where("endloc LIKE ?", "#{params[:searchto]}%")
# then search for end locations in the result of start location.
Also check: HERE

Related

Rails how to use where method for search or return all?

I am trying to do a search with multiple attributes for Address at my Rails API.
I want to search by state, city and/or street. But user doesn't need to send all attributes, he can search only by city if he wants.
So I need something like this: if the condition exists search by condition or return all results of this condition.
Example:
search request: street = 'some street', city = '', state = ''
How can I use rails where method to return all if some condition is nil?
I was trying something like this, but I know that ||:all doesn't work, it's just to illustrate what I have in mind.:
def get_address
address = Adress.where(
state: params[:state] || :all,
city: params[:city] || :all,
street: params[:street] || :all)
end
It's possible to do something like that? Or maybe there is a better way to do it?
This is a more elegant solution using some simple hash manipulation:
def filter_addesses(scope = Adress.all)
# slice takes only the keys we want
# compact removes nil values
filters = params.permit(:state, :city, :street).to_h.compact
scope = scope.where(filters) if filters.any?
scope
end
Once you're passing a column to where, there isn't an option that means "on second thought don't filter by this". Instead, you can construct the relation progressively:
def get_address
addresses = Address.all
addresses = addresses.where(state: params[:state]) if params[:state]
addresses = addresses.where(city: params[:city]) if params[:city]
addresses = addresses.where(street: params[:street]) if params[:street]
addresses
end
I highly recommend using the Searchlight gem. It solves precisely the problem you're describing. Instead of cluttering up your controllers, pass your search params to a Searchlight class. This will DRY up your code and keep your controllers skinny too. You'll not only solve your problem, but you'll have more maintainable code too. Win-win!
So in your case, you'd make an AddressSearch class:
class AddressSearch < Searchlight::Search
# This is the starting point for any chaining we do, and it's what
# will be returned if no search options are passed.
# In this case, it's an ActiveRecord model.
def base_query
Address.all # or `.scoped` for ActiveRecord 3
end
# A search method.
def search_state
query.where(state: options[:state])
end
# Another search method.
def search_city
query.where(city: options[:city])
end
# Another search method.
def search_street
query.where(street: options[:street])
end
end
Then in your controller you just need to search by passing in your search params into the class above:
AddressSearch.new(params).results
One nice thing about this gem is that any extraneous parameters will be scrubbed automatically by Searchlight. Only the State, City, and Street params will be used.

building a simple search form in Rails?

I'm trying to build a simple search form in Ruby on Rails, my form is simple enough basically you select fields from a series of options and then all the events matching the fields are shown. The problem comes when I leave any field blank.
Here is the code responsible for filtering the parameters
Event.joins(:eventdates).joins(:categories).where
("eventdates.start_date = ? AND city = ? AND categories.name = ?",
params[:event][:date], params[:event][:city], params[:event][:category]).all
From what I get it's that it looks for events with any empty field, but since all of them have them not empty, it wont match unless all 3 are filled, another problem arises when I try to say, look events inside a range or array of dates, I'm clueless on how to pass multiple days into the search.
I'm pretty new to making search forms in general, so I don't even know if this is the best approach, also I'm trying to keep the searches without the need of a secialized model.
Below is probably what you are looking for. (Note: If all fields all blank, it shows all data in the events table linkable with eventdates and categories.)
events = Event.joins(:eventdates).joins(:categories)
if params[:event]
# includes below where condition to query only if params[:event][:date] has a value
events = events.where("eventdates.start_date = ?", params[:event][:date]) if params[:event][:date].present?
# includes below where condition to query only if params[:event][:city] has a value
events = events.where("city = ?", params[:event][:city]) if params[:event][:city].present?
# includes below where condition to query only if params[:event][:city] has a value
events = events.where("categories.name = ?", params[:event][:category]) if params[:event][:category].present?
end
To search using multiple days:
# params[:event][:dates] is expected to be array of dates.
# Below query gets converted into an 'IN' operation in SQL, something like "where eventdates.start_date IN ['date1', 'date2']"
events = events.where("eventdates.start_date = ?", params[:event][:dates]) if params[:event][:dates].present?
It will be more easy and optimised . If you use concern for filter data.
Make one concern in Model.
filterable.rb
module Filterable
extend ActiveSupport::Concern
module ClassMethods
def filter(filtering_params)
results = self.where(nil)
filtering_params.each do |key, value|
if column_type(key) == :date || column_type(key) ==
:datetime
results = results.where("DATE(#{column(key)}) = ?",
Date.strptime(value, "%m/%d/%Y")) if
value.present?
else
results = results.where("#{column(key)} Like ? ", "%#{value}%") if
value.present?
end
end
results
end
def resource_name
self.table_name
end
def column(key)
return key if key.split(".").count > 1
return "#{resource_name}.#{key}"
end
def column_type(key)
self.columns_hash[key].type
end
end
end
Include this concern in model file that you want to filter.
Model.rb
include Filterable
In your controller Add this methods
def search
#resources = Model.filter(class_search_params)
render 'index'
end
def class_search_params
params.slice(:id,:name) #Your field names
end
So, It is global solution. You dont need to use query for filter. just add this concern in your model file.
That's it.

More than one ActiveRecord query at once?

Here's an action in my controller. What it currently does is display all Guides that have a least any spelling of the word 'abyss' in it. What I'd like to do is display all guides that have either any spelling of 'abyss' or any spelling of 'cat' in it as well.
I've tried all sorts of '%cat%' combinations, but can't find the right place to put it.
How do I make this work?
def abyss
t = Guide.arel_table
#guides = Guide.where(t[:title].matches('%abyss%'))
end
Try with or as follows:
def abyss
t = Guide.arel_table
#guides = Guide.where(t[:title].matches('%abyss%').or(t[:title].matches('%cat%')))
end
You can use find_by_sql to simplify such queries:
def abyss
#guides = Guide.find_by_sql(["select * from guides where title LIKE ? OR title LIKE ?", '%abyss%', '%cat%'])
end

How can I search a table based on multiple search criteria without require said criteria?

I have created a table that houses product brochures. I would like to allow the user to search the table based on three drop down menus (product type, carrier, concept). I have created the menus and the controller currently passes through the params correctly. If the user search by all 3 criteria, the search displays correctly. If the user chooses only one or two search options however, the result is always nothing. I understand why this is happening (the model is trying to search by all three criteria and when one is missing, it simply searches nil in that field), however I'm sure the correct solution. Please help! My model is below...thank you
def self.search (search_product_type, search_carrier, search_concept)
if search_product_type.blank? && search_carrier.blank? && search_concept.blank?
scoped
else
Ad.where(carrier_id: search_carrier)
.where(product_type_id: search_product_type)
.where(concept: search_concept)
end
end
As #Deefour said in the comments you should use a gem. But, you can also make something like this:
def self.search (search_product_type, search_carrier, search_concept)
if search_product_type.blank? && search_carrier.blank? && search_concept.blank?
scoped
else
tmp = {}
if search_carrier.present?
tmp[:carrier_id] = search_carrier
end
if search_product_type.present?
tmp[:product_type_id] = search_product_type
end
if search_carrier.present?
tmp[:concept] = search_concept
end
Ad.where(tmp)
end
end

Rails 3 multiple parameter filtering using scopes

Trying to do a basic filter in rails 3 using the url params. I'd like to have a white list of params that can be filtered by, and return all the items that match. I've set up some scopes (with many more to come):
# in the model:
scope :budget_min, lambda {|min| where("budget > ?", min)}
scope :budget_max, lambda {|max| where("budget < ?", max)}
...but what's the best way to use some, none, or all of these scopes based on the present params[]? I've gotten this far, but it doesn't extend to multiple options. Looking for a sort of "chain if present" type operation.
#jobs = Job.all
#jobs = Job.budget_min(params[:budget_min]) if params[:budget_min]
I think you are close. Something like this won't extend to multiple options?
query = Job.scoped
query = query.budget_min(params[:budget_min]) if params[:budget_min]
query = query.budget_max(params[:budget_max]) if params[:budget_max]
#jobs = query.all
Generally, I'd prefer hand-made solutions but, for this kind of problem, a code base could become a mess very quickly. So I would go for a gem like meta_search.
One way would be to put your conditionals into the scopes:
scope :budget_max, lambda { |max| where("budget < ?", max) unless max.nil? }
That would still become rather cumbersome since you'd end up with:
Job.budget_min(params[:budget_min]).budget_max(params[:budget_max]) ...
A slightly different approach would be using something like the following inside your model (based on code from here:
class << self
def search(q)
whitelisted_params = {
:budget_max => "budget > ?",
:budget_min => "budget < ?"
}
whitelisted_params.keys.inject(scoped) do |combined_scope, param|
if q[param].nil?
combined_scope
else
combined_scope.where(whitelisted_params[param], q[param])
end
end
end
end
You can then use that method as follows and it should use the whitelisted filters if they're present in params:
MyModel.search(params)

Resources