Как получить список всех тегов при использовании драгоценного камня "act-as-taggable-on" в Rails (а не в процентах)
Я установил acts-as-taggable-on
gem в моей модели следующим образом:
acts_as_taggable_on :deshanatags
Он использует контекст deshanatags
. Теперь мне нужно получить список всех тегов (а не только те, которые были назначены для одного элемента. Мне нужно все) в этом контексте в следующем формате:
[
{"id":"856","name":"House"},
{"id":"1035","name":"Desperate Housewives"}
]
Как я могу это сделать?
Я старался следовать многим учебным пособиям, но попал в тупики, потому что большинство из них написано для Rails 3. Rails для некоторых изменений в модели, таких как удаление attr_accessor, затрудняет мне понимание этих обучающих программ. Поэтому, пожалуйста, помогите.
Просто я пытаюсь добавить вход в токен JQuery (http://loopj.com/jquery-tokeninput/) в мое приложение
PS: Через таблицу тегов, есть ли способ получить список тегов, таких как вывод Tag.all, путем фильтрации контекста?
Ответы
Ответ 1
Теги хранятся в таблице тегов, к которой вы получаете доступ из вашей программы, например,
ActsAsTaggableOn::Tag.all
Если вам нужна дополнительная информация об использовании тегов, есть также таблица
ActsAsTaggableOn::Tagging
который содержит ссылки на то, где используется каждый тег, включая его контекст
Чтобы применить это к вашему примеру, вы можете использовать
ActsAsTaggableOn::Tagging.includes(:tag).where(context: 'deshanatags').map { |tagging| { 'id' => tagging.tag_id.to_s, 'name' => tagging.tag.name } }.uniq
Объясним различные части этого утверждения:
- "includes" гарантирует, что разные теги "загружены", другими словами, что вместо загрузки n + 1 записей в базе данных будет выполняться всего 2 запроса
- 'where' ограничивает записи теми, у кого данный контекст
- 'map' преобразует результирующий массив записей в новый массив, содержащий хеши, о которых вы просили в своей проблеме, с идентификатором, сопоставленным с идентификатором тега, и именем, сопоставленным с именем тега
- наконец, "uniq" гарантирует, что у вас нет двойников в вашем списке.
Чтобы справиться с дополнительной проблемой, будучи тегами без тега, вы можете расширить предложение where до
where("(context = 'deshanatags') AND (tag_id IS NOT NULL)")
Ответ 2
Я лично считаю, что оба решения будут медленными, если у вас есть много тэгов для извлечения, поскольку есть много отдельных операторов select.
Я бы сделал это следующим образом:
ActsAsTaggableOn::Tagging.includes(:tag).where(context: 'deshanatags').uniq.pluck(:id, :name)
Если вы на рубине 1.9 +
Таким образом, вы просто закончите:
SELECT DISTINCT "taggings"."id", name FROM "taggings" LEFT OUTER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."context" = 'deshanatags'
Быстрое и легкое imo
Ответ 3
Используя модель ActsAsTaggableOn::Tagging
, вы можете получить список всех тегов и отфильтровать их в соответствии с контекстом, а затем отформатировать их следующим образом:
ActsAsTaggableOn::Tagging.all
.where(context: "deshanatags")
.map {|tagging| { "id" => "#{tagging.tag.id}", "name" => tagging.tag.name } }
where
даст нам результат всех тегов для данного контекста, которые мы затем перебираем с помощью map
, извлекаем связанный тег для каждого тега в нашем результате и получаем атрибуты id и name.
Обязательно привяжите методы напрямую (не к нескольким строкам), если вы не используете ruby 1.9 +
Затем вы можете вызвать .to_json на результат, чтобы получить правильно отформатированный json-объект, который вы можете использовать
изменить
Я обновил сообщение, чтобы уточнить, что делает каждый оператор, а также обновил формат нашего окончательного результата, чтобы использовать строки как ключи вместо символов