Эквивалент сложного SQL-запроса в Rails 3

Учитывая следующие модели:

class Recipe < ActiveRecord::Base
  has_many :recipe_ingredients
  has_many :ingredients, :through => :recipe_ingredients
end

class RecipeIngredient < ActiveRecord::Base
  belongs_to :recipe
  belongs_to :ingredient
end

class Ingredient < ActiveRecord::Base
end

Как я могу выполнить следующий SQL-запрос, используя Arel в Rails 3?

SELECT * FROM recipes WHERE NOT EXISTS (
  SELECT * FROM ingredients WHERE 
    name IN ('chocolate', 'cream') AND 
    NOT EXISTS (
      SELECT * FROM recipe_ingredients WHERE 
        recipe_ingredients.recipe_id = recipes.id AND 
        recipe_ingredients.ingredient_id = ingredients.id))

person Bryan Ash    schedule 15.06.2010    source источник
comment
Вы можете преломить это, чтобы использовать соединения? подвыборки на самом деле не существуют в рельсах, за исключением выполнения двух запросов и использования Ruby, IMO   -  person Scott Schulthess    schedule 15.06.2010


Ответы (1)


Я не уверен, как сделать реляционное деление с помощью Arel или ActiveRecord. Если допустимо выполнить два запроса, это будет эквивалентно:

with_scope(includes(:recipes)) do
  cream_recipes = Ingredient.where(:name => "cream").first.recipes
  chocolate_recipes = Ingredient.where(:name => "chocolate").first.recipes
end
@recipes_with_chocolate_and_cream = cream_recipes & chocolate_recipes

Или вы можете просто передать SQL напрямую, используя find_by_sql.

person Awgy    schedule 15.06.2010
comment
Я думаю, что этот метод делает код очень читаемым, и любой другой разработчик легко его понимает и быстро понимает. +1 - person StevenMcD; 23.07.2010
comment
Вы выигрываете бонус ... без сомнения, лучший ответ! - person Bryan Ash; 28.07.2010