清理基于多个选项进行查询的混乱代码



我正在使用Rails,但这里的潜在问题更广泛地适用。我的 Web 应用程序上有一个报表页面,允许用户指定他们正在过滤的内容,并根据这些过滤器 (MongoDB) 查询数据库。

数据以酒店为依据,用户必须首先选择酒店的区域(state_onestate_twostate_three),然后选择酒店的状态(planningunder_constructionoperational),然后是可选的标准、价格范围(200300400)。 用户可以选择其中每个选项中的多个。

我目前的做法是创建一个空数组,遍历每个区域,如果用户选择了该区域,则将该区域推送到数组中。然后,我遍历该数组,并评估这些区域中酒店的状态,如果任何酒店具有用户选择的状态,则我将该酒店添加到新的空数组中。 然后我对价格范围做同样的事情。

这有效,但代码令人反感地混乱,下面是一个代码示例:

def find_hotel
hotels = find_all_hotels
first_array = []
hotels.each do |hotel|
if params[:options][:region].include? 'state_one' and hotel.state == :one
first_array.push(hotel)
elsif params[:options][:region].include? 'state_two' and hotel.state == :two
first_array.push(hotel)
elsif params[:options][:region].include? 'state_three' and hotel.state == :three
first_array.push(hotel)
end
end
second_array = []
first_array.each do |hotel|
if params[:options][:region].include? 'planning' and hotel.status == :planning
first_array.push(hotel)
elsif params[:options][:region].include? 'under_construction' and hotel.status == :under_construction
first_array.push(hotel)
elsif params[:options][:region].include? 'operational' and hotel.status == :operational
first_array.push(hotel)
end
end
third_array = []
second_array.each do |hotel|
# More of the same here, this could go on forever
end
end

有哪些更好的方法可以实现这一目标?

这个怎么样:

STATES   = [:one, :two, :three]
STATUSES = [:planning, :under_construction, :operational]
PRICES   = [200, 300, 400]
def find_hotel
region = params[:options][:region]
first_array  = set_array(region, find_all_hotels, STATES, :state)
second_array = set_array(region, first_array, STATUSES, :status)
third_array  = set_array(region, second_array, PRICES, :price_range)
end
def set_array(region, array, options, attribute)
array.each_with_object([]) do |element, result|
options.each do |option|
result << element if region.include?(option) && element[attribute] == option
end
end
end

更新

set_array添加了attribute参数,以使代码适用于更新的示例。

由于second_array是空的,所以通过迭代它得到的任何内容(也许是third_array)也将是空的。

def find_hotel
hotels = find_all_hotels
first_array = hotels
.select{|hotel| params[:options][:region].include?("state_#{hotel.state}")}
first_array += first_array
.select{|hotel| params[:options][:region].include?(hotel.status.to_s)}
second_array = third_array = []
...
end

最新更新