I will start by saying that you don't really need sort_by!
You can achieve the same thing with:
ar1.sort_by { |e| ar2.index(e) || Float::INFINITY }
with an approach similar to:
result = ((ar2 & ar1) + ar1).uniq
Which is much faster.
Here is a simple benchmark to back this suggestion.
require 'benchmark'
ar1 = 100_000.times.map {|x|( 100_000_000 * rand).to_i }.uniq
ar2 = 100_000.times.map {|x|( 100_000_000 * rand).to_i }.uniq
puts ar1.size
puts ar2.size
Benchmark.bm do |x|
result_2 = []
result_1 = []
x.report('sort') do
result_2 = ar1.sort_by { |e| ar2.index(e) || Float::INFINITY }
result_2.size
end
x.report('array') do
result_1 = ((ar2 & ar1) + ar1).uniq
result_1.size
end
puts result_1.size
puts result_2.size
puts result_1 == result_2
end
Gives some nice results
user system total real
sort 45.287331 0.012233 45.299564 ( 45.539641)
array 0.010782 0.004000 0.014782 ( 0.014792)
I omitted some validation output.
Now for the ActiveRecord part.
Depending on the ar2 collection size you can retrieve the ids and sort the second query by that. Given that ar1 = first_query.order(first_order)
ar2_ids = second_query.pluck(:id)
ar1 = first_query.order("FIELD(id, #{ar2_ids.join(',')}), first_order")
This will keep the ar2 first and the others later.
You will need to investigate the size of ar2 because depending on your database it may be suboptimal to provide an order query with some thousands of ids.
After some thought on the problem, I would choose the array manipulation approach to keep things simple. I wouldn't go for the database solutions because it would most probably mess up the readability of the queries, way too much.
It all depends on the details of your problem! I hope this helps.