Это работает:
scope :highest_rated, includes(:ratings).group('product_id').order('AVG(ratings.rating) DESC')
Чтобы получить только продукты с существующим рейтингом:
scope :highest_rated, includes(:ratings).group('product_id').where('ratings.rating IS NOT NULL').order('AVG(ratings.rating) DESC')
РЕДАКТИРОВАТЬ: вышеописанное не будет работать в PostgreSQL.Я использовал это вместо этого (который работает как в SQLite, так и в PostgreSQL):
scope :highest_rated, where("products.id in (select product_id from ratings)").group('products.id, products.name, products.all_other_fields').joins(:ratings).order('AVG(ratings.rating) DESC')