I'd consider using Arel for this kind of problem to be overly complicated. ActiveRecord itself, which is a layer above Arel can solve this quite comfortably.
I assume you have the following models
class Recipe
has_many :recipe_ingredients
...
end
class RecipeIngredient
has_one: :recipe
has_one: :ingredient
...
end
class Ingredient
has_many :recipe_ingredients
...
end
In order to get the recipes ordered by the number of ingredients you'll have to generate the following SQL statement:
SELECT
recipes.id
...
, recipes.[last_column_name]
# optionally
, COUNT(*) ingredients_count
FROM
recipes
OUTER JOIN
recipe_ingredients
ON
recipe_ingredients.recipe_id = recipe.id
GROUP BY
ingredient_count DESC
which can be done by
Recipe
.joins(:recipe_ingredients)
.group(Recipe.column_names)
.select(Recipe.column_names, 'COUNT(*) ingredients_count')
.order('ingredients_count DESC') # Or ASC
The Recipe instances returned will be sorted by the number of ingredients. They will also have an additional method ingredients_count
which returns the number of ingredients.
This could also be placed into a scope inside the Recipe class.
def self.ordered_by_ingredients_count
joins(:recipe_ingredients)
.group(column_names)
.select(column_names, 'COUNT(*) ingredients_count')
.order('ingredients_count DESC') # Or ASC
end
For the reverse, number of recipes an ingredient is in, just swap some names:
Ingredient
.joins(:recipe_ingredients)
.group(Ingredient.column_names)
.select(Ingredient.column_names, 'COUNT(*) recipe_count')
.order('recipe_count DESC') # Or ASC