Трюк было бы удалить пустые значения, сделать немного предварительной обработки (и, возможно, валидация) данных, а затем передать Params к статье where
,
Чтобы помочь с обработкой диапазонов дат, вы можете создать метод, который проверяет обе даты предусмотрены и преобразуются в диапазоне:
def convert_to_range(start_date, end_date)
if start_date && end_date
price_from = Date.parse(price_from)
price_to = Date.parse(price_to)
price_from..price_to
end
rescue ArgumentError => e
# If you're code reaches here then the user has invalid date and you
# need to work out how to handle this.
end
Тогда ваше действие контроллера может выглядеть примерно так:
# select only the params that are need
car_params = params.slice(:car_model_id, :used, :year_from, :year_to, :price_from, :price_to, :condition)
# do some processing of the data
year_from = car_params.delete(:year_from).presence
year_to = car_params.delete(:year_to).presence
car_params[:price] = convert_to_range(year_from, year_to)
price_from = car_params.delete(:price_from).presence
price_to = car_params.delete(:price_to).presence
car_params[:price] = convert_to_range(price_from, price_to)
# select only params that are present
car_params = car_params.select {|k, v| v.present? }
# search for the cars
@cars = Car.where(car_params)
Кроме того, я уверен, что значение used
будет автоматически приводиться к булева для вас, когда его предоставлена where
.
Также @cars
является ActiveRecord::Relation
, который не имеет метода errors
. Возможно, вы хотите дать разные результаты в зависимости от того, вернулись ли какие-либо автомобили?
Например: @cars.any?
(или @cars.load.any?
, если вы не хотите, чтобы выполнить два запроса, чтобы забрать машины и проверить, существуют ли автомобили)
Edit:
Как упомянуто mu is too short вы можете также чистые вверх по вашему коду путем цепочки where
условий и scopes. Области применения помогают перемещать функциональность из контроллера и в модель, что увеличивает возможность повторного использования функциональности.
E.g.
class Car > ActiveRecord::Base
scope :year_between, ->(from, to) { where(year: from..to) }
scope :price_between, ->(from, to) { where(price: from..to) }
scope :used, ->(value = true) { where(used: used) }
end
Тогда в контроллере:
# initial condition is all cars
cars = Cars.all
# refine results with params provided by user
cars = cars.where(car_model_id: params[:car_model_id]) if params[:car_model_id].present?
cars = cars.year_between(params[:year_from], params[:year_to])
cars = cars.price_between(params[:price_from], params[:price_to])
cars = cars.used(params[:used])
cars = cars.where(condition: params[:condition]) if params[:condition].present?
@cars = cars
не Может быть стоит ничего, что 'M.where (а: 'B', C: 'd')' является такой же, как 'M.where (a: 'b'). где (c: 'd') 'или даже' ms = M.where (a: 'b'); ms = ms.where (c: 'd') ', поэтому вы можете достаточно легко разделить общие части ветвей' if' и 'else'. Немного более гибкий, чем манипулирование хешем, так как вы можете бросить в области. –
Я застрял в '' 'car_params.delete''' Отладка с консоли rails:' '' 2.2.3: 035> car_params [: year] = car_params.delete (: year_from) .. car_params.delete (: year_to) => nil..nil 2.2.3: 037> Car.where (car_params) Автомобильная нагрузка (0,1 мс) ВЫБРАТЬ «автомобили». * ОТ «Автомобили» ГДЕ «автомобили». «car_model_id» = ? И "автомобили". "Used" =? И "автомобили". "Condition" =? И («автомобили». «Год» МЕЖДУ И?) И («автомобили». «Цена» МЕЖДУ И?) [[car_model_id ", 1], [" used ", true], [" condition "," perfect "], [" year ", nil], [" year ", nil], [" price ", nil ], ["price", nil]] => # '' ' –
Freeminder
Запрос поставляется с пустыми параметрами:' '' "year_from" => "", "year_to" => "," price_from "=>" "," price_to "=>" "' '' И метод .delete преобразует его в '' '' '''' – Freeminder