Rails 4: Фильтр с тегами

Я следовал руководству и создал метод маркировки на своем веб-сайте с рецептами. У меня есть следующие модели:

class Recipe < ActiveRecord::Base
    has_many :taggings
    has_many :tags, through: :taggings
end

class Tag < ActiveRecord::Base
    has_many :taggings
    has_many :recipes, through: :taggings
end

class Tagging < ActiveRecord::Base
  belongs_to :tag
  belongs_to :recipe
end

В своем указателе рецептов я хотел бы создать фильтр, который выбирает рецепты с тегами ALL, выбранными пользователем.

У меня есть способ вытащить все рецепты с заданным тегом:

def self.tagged_with(name)
    Tag.find_by_name!(name).recipes
end

... и я пытаюсь использовать inject для объединения нескольких тегов в один запрос:

def self.new_filter(tags) # tags is an array
    tags.inject(Recipe.all) { |res, arg| res.tagged_with(arg) }
end

Но это не возвращает рецепты со всеми тегами, он возвращает рецепты с последним тегом в массиве тегов. Как это исправить, чтобы возвращались только рецепты со всеми тегами?


person Jeremy Thomas    schedule 14.10.2016    source источник
comment
Это очень похожий вопрос на stackoverflow.com/questions/17920505/, у которого есть ответ, который может, по крайней мере, указать вам правильное направление.   -  person Jim    schedule 15.10.2016


Ответы (1)


В этой строке tags.inject(Recipe.all) { |res, arg| res.tagged_with(arg) } проблема заключается в том, что вы возвращаете Recipies после того, как он извлекает его с помощью метода tagged_with, на этом операция заканчивается. Таким образом, для каждого элемента массива tags inject выполнит операцию и вернет результат, но не передаст его обратно для следующей итерации операции inject над tags. В конце вы получите все, что он вернет после выполнения запроса для последнего тега.

вы можете сделать что-то вроде этого:

def self.new_filter(tags) # tags is an array
  res = Recipe.all;
  tags.inject({}) { |all_res, arg| all_res[arg] = res.tagged_with(arg); all_res }
end

После этого вы получите хэш с ключом в качестве имени тега и рецептами в виде значений, например: my_recipes = {:chinese => *all data returned for chinese*}

ИЛИ вы можете сделать что-то вроде

def self.new_filter(tags) # tags is an array
 Recipe.joins(:tags).where('tags.name IN (?)', tags)
end

PS: я не тестировал код, при необходимости внесите необходимые коррективы.

person Sajan    schedule 15.10.2016