在进行查询之前,我正在检查空参数。 params [:car_model_id] 只有1次检查。我可以想象如果我要为其他参数添加更多检查,那么会有一堆if-else语句。它看起来并不好看,我认为它可以进行优化。但是怎么样?这是控制器的代码:
class CarsController < ApplicationController
def search
if params[:car_model_id].empty?
@cars = Car.where(
used: ActiveRecord::Type::Boolean.new.cast(params[:used]),
year: params[:year_from]..params[:year_to],
price: params[:price_from]..params[:price_to],
condition: params[:condition]
)
else
@cars = Car.where(
used: ActiveRecord::Type::Boolean.new.cast(params[:used]),
car_model_id: params[:car_model_id],
year: params[:year_from]..params[:year_to],
price: params[:price_from]..params[:price_to],
condition: params[:condition]
)
end
if @cars
render json: @cars
else
render json: @cars.errors, status: :unprocessable_entity
end
end
end
答案 0 :(得分:1)
诀窍是删除空白值,对数据进行一些预处理(并可能验证),然后将参数传递给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?
如果您不想执行两个查询来获取汽车并检查汽车是否存在)
修改强>
正如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