Skip to content

Instantly share code, notes, and snippets.

@CharlyJazz
Created July 20, 2023 01:18
Show Gist options
  • Save CharlyJazz/79898de6a1f252f1f526e3f5cdc238ab to your computer and use it in GitHub Desktop.
Save CharlyJazz/79898de6a1f252f1f526e3f5cdc238ab to your computer and use it in GitHub Desktop.
prueba.rb
class Api::CarSearch
include SearchObject.module(:paging)
include SearchObject.module(:sorting)
per_page 1
min_per_page 1
max_per_page 50
sort_by :price
option(:price_min) { |scope, value| scope.where('price > ?', value) }
option(:price_max) { |scope, value| scope.where('price < ?', value) }
# https://stackoverflow.com/questions/11823689/how-to-make-sure-a-record-is-always-at-the-top-in-a-given-resultset-in-mysql
# https://stackoverflow.com/questions/48743316/ruby-on-rails-active-record-sort-and-put-specific-row-to-the-top
# https://stackoverflow.com/questions/23620615/how-to-sort-activerecord-query-by-specific-prority
# Implement Priority sending using the order clause.
# ------
# With this approach I can paginate easily using SQL and avoid merge manually differents sources of cars and then paginate it manually
# ------
# This technique are respeting the price_min and price_max filters but the perfect match and good match
# will be in the top no matter if the price dont fit with the filter rules
def initialize(options={})
counter_priority = 0
super options.merge(scope: Car.order(
Arel.sql(
"
CASE
#{
options[:top_results_id][:car_perfect_match_ids].map do |id|
counter_priority += 1
"WHEN (id = #{id}) THEN #{counter_priority} "
end.join(' ') +
options[:top_results_id][:car_good_match_ids].map do |id|
counter_priority += 1
"WHEN (id = #{id}) THEN #{counter_priority} "
end.join(' ') +
options[:top_results_id][:car_external_recommendation_ids].map do |id|
counter_priority += 1
"WHEN (id = #{id}) THEN #{counter_priority} "
end.join(' ')
}
END ASC"
)
).all)
end
end
class Api::CarSearchController < ApplicationController
def index
@user = User.find(params[:user_id])
# 1. On top it should be cars with perfect_match label. This cars have match
# with user preferred car brands ( user.preferred_brands.include?(car.brand) == true)
# and with preferred price (user.preferred_price_range.include?(car.price) == true).
car_perfect_match_ids = (20..25).to_a
# 2. Then we should have good_match offers. These offers have the only user
# preferred car brands (user.preferred_brands.include?(car.brand) == true).
car_good_match_ids = (40..45).to_a
# 3. Then goes top 5 cars suggested by external recommendation service API
# (they can also be matched as perfect and good matches).
car_external_recommendation_ids = (60..65).to_a
# 4. Then goes all other cars sorted by price (ASC).
@search = Api::CarSearch.new(
filters: get_search_filter_params.merge(
{ sort: 'price asc' }
),
page: params[:page],
per_page: params[:per_page],
top_results_id: {
car_perfect_match_ids: car_perfect_match_ids,
car_good_match_ids: car_good_match_ids,
car_external_recommendation_ids: car_external_recommendation_ids
}
)
end
private
def get_search_filter_params
params.slice(:user_id, :query, :price_min, :price_max, :free)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment