I have a table vehicles that has_one vehicle_size. The VehicleSize model has a column in the table size, a String. Here are examples of a size value: 12ft, 19ft, EV. The goal is to sort vehicles based on the size from the vehicle_sizes table.
Here is my current solution:
def order_by_size(resources)
return resources unless context.params[:by_size] == 'asc' || context.params[:by_size] == 'desc'
if context.params[:by_size] == 'desc'
resources.joins(:vehicle_size).group('vehicle_sizes.size').order('vehicle_sizes.size DESC')
else
resources.joins(:vehicle_size).group('vehicle_sizes.size').order('vehicle_sizes.size ASC')
end
end
The solution above performs sorting. First, however, I need to push all zero values to the end regardless if the order is desc or asc (* zero means EV or any other string without numbers).
I tried to sort records with .sort { ... }, but it returns an array instead of active relation, with is necessary for me.
Solution where I get an array with sort:
def order_by_size(resources)
return resources unless context.params[:by_size] == 'asc' || context.params[:by_size] == 'desc'
if context.params[:by_size] == 'desc'
resources.joins(:vehicle_size).group('vehicle_sizes.size').sort do |x, y|
if x.vehicle_size.size.to_i.zero?
1
elsif y.vehicle_size.size.to_i.zero?
-1
else
y.vehicle_size.size.to_i <=> x.vehicle_size.size.to_i
end
end
else
resources.joins(:vehicle_size).group('vehicle_sizes.size').sort do |x, y|
if x.vehicle_size.size.to_i.zero?
1
elsif y.vehicle_size.size.to_i.zero?
-1
else
x.vehicle_size.size.to_i <=> y.vehicle_size.size.to_i
end
end
end
end
How can I modify my first or second solution to return an active relation where all String (zeros) will be pushed to the end regardless of sorting? Am I missing something here?
Many thanks for considering my request.
CodePudding user response:
VehicleSize.order(Arel.sql("size = 'EV', size"))
or
VehicleSize.order(Arel.sql("size = 'EV', size desc"))
This way records with size = EV will be last, but others will be sorted as you need
Result will be relation
If you need specify table name, you can use vehicle_sizes.size instead of size
If you have few values without number (EV and ED here) you can do something like this to avoid hardcode
zero_array = %w[EV ED]
VehicleSize.order(
VehicleSize.sanitize_sql_for_order([Arel.sql("size IN (?), size DESC"), zero_array])
)
CodePudding user response:
You can add a new field to the order
vehicle_sizes.size = 0, vehicle_sizes.size DESC
Or
vehicle_sizes.size <> 0, vehicle_sizes.size DESC
