如何根据指定数组的排序规则对Active Record对象进行排序
实现方案
前置修正
你定义目标品牌数组的写法有语法问题:%w 字面量默认用空格分隔元素,不需要额外加逗号,否则生成的元素会自带逗号后缀,修正为:
brands = %w[Toyota Nissan Lexus Kia Mazda Honda BMW Range Rover Chevrolet Mitsubishi]
方案1:内存中对已查询的Active Record对象排序
适合已经把UsedCar对象列表查询到内存中的场景,用sort_by即可实现,提前把品牌和排序权重的映射做成哈希,查询效率更高:
# 提前生成品牌对应排序位置的映射,查找复杂度O(1) brand_order = brands.each_with_index.to_h # 排序,不在目标数组中的品牌默认排到最后,想要排到前面就把Float::INFINITY改成-Float::INFINITY sorted_cars = used_cars.sort_by { |car| brand_order[car.brand] || Float::INFINITY }
方案2:SQL查询层面直接排序
适合还未查询数据库,直接在查询阶段完成排序的场景,避免后续内存操作,性能更好:
# 生成CASE WHEN排序逻辑 order_clause = brands.each_with_index.map do |brand, index| "WHEN brand = '#{ActiveRecord::Base.sanitize_sql(brand)}' THEN #{index}" end.join(' ') # 不在目标列表的品牌统一排在最后 order_sql = Arel.sql("CASE #{order_clause} ELSE #{brands.size} END") # 查询时直接排序 sorted_cars = UsedCar.where(你的查询条件).order(order_sql)
注:这里用
sanitize_sql对品牌值做转义,避免SQL注入风险,如果品牌数组是你自己维护的固定值可以省略转义步骤。
内容的提问来源于stack exchange,提问作者Haseeb Ahmad
相关产品推荐
相关产品推荐

