Now that I finally understand the question (I hope), here's the bad news: SQL doesn't have any simple commands for sorting in the manner you require - ORDER BY alone isn't going to suffice. Because of this, ActiveRecord doesn't either provide a simple solution (ActiveRecord is simply an ORM with a good/very good SQL statement generator). What you require is quite complex for any ORM to do efficiently.
The good news is that you can do this with a complete understanding how you can use SQL to accomplish this, and a bit of work to inform AR what you are trying to do. First, the SQL.
There are various approaches to sort by a MAX of a collection of associated rows, and the most efficient will vary by DBMS and the actual data. Because you are using PostgreSQL, you might want to use a window function to accomplish this. The problem is that using a window function to work cleanly with eager loading is going to be extremely difficult. So what other options are there using vanilla SQL? One simple approach involves using NOT EXISTS:
SELECT /* some-eager-loaded-fields */
FROM foos
LEFT JOIN bars ON foos.id = bars.foo_id
AND NOT EXISTS (
SELECT 1 FROM bars b2
WHERE b2.foo_id = bars.foo_id AND b2.created_at > bars.created_at
)
ORDER BY bars.value, foos.name
The NOT EXISTS will exclude any bars where a greater created_at
exists for that foo_id
. This leaves you with the only bar that has no greater created_at
- the MAX. Now that we have the query, how would we generate that in AR?
The subquery would look like this (using Arel to help format the alias correctly):
b2 = Bar.arel_table.alias('b2')
Bar.select('1').from(b2).where('b2.foo_id = bars.foo_id AND b2.created_at > bars.created_at')
This can now be used to determine most recent:
def Bar < AR::Base
def self.most_recent
b2 = arel_table.alias('b2')
where Bar.select('1').from(b2).
where('b2.foo_id = bars.foo_id AND b2.created_at > bars.created_at').
exists.not
end
end
And your most_recent_bar
association:
def Foo < AR::Base
has_many :bars
has_one :most_recent_bar, ->{ merge(Bar.most_recent) }, class_name: 'Bar'
end
Now your query should just work:
Foo.includes(:most_recent_bar).order('bars.value asc, foos.name asc')