Как получить список всех тегов при использовании драгоценного камня «действует как пометка» в Rails (не подсчеты)

Я установил драгоценный камень acts-as-taggable-on в своей модели следующим образом:

 acts_as_taggable_on :deshanatags

Он использует контекст deshanatags. Теперь мне нужно получить список всех тегов (не только назначенных для одного элемента. Мне нужны все) в данном контексте в следующем формате:

[
    {"id":"856","name":"House"},
    {"id":"1035","name":"Desperate Housewives"}
]

Как я могу это сделать?

Я пытался следовать многим руководствам, но зашел в тупик, потому что большинство из них написано для Rails 3. Rails для имеет некоторые изменения в модели, такие как удаление attr_accessor, что затрудняет мне понимание этих руководств. Пожалуйста, помогите.

Просто я пытаюсь добавить ввод Jquery Token (http://loopj.com/jquery-tokeninput/) в свое приложение.

PS: Есть ли способ с помощью таблицы тегов получить список тегов, например вывод Tag.all, путем фильтрации контекста?


person THpubs    schedule 28.03.2014    source источник


Ответы (4)


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

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

Давайте объясним различные части этого утверждения:

  • «включает» гарантирует, что различные теги «загружаются с нетерпением», другими словами, вместо загрузки n + 1 записей в базу данных будут выполняться только 2 запроса.
  • 'где' ограничивает записи теми, которые имеют заданный контекст
  • «карта» преобразует полученный массив записей в новый массив, содержащий хэши, которые вы запросили в своей проблеме, с идентификатором, сопоставленным с идентификатором тега, и именем, сопоставленным с именем тега.
  • наконец, «uniq» гарантирует, что в вашем списке нет двойников

Чтобы также справиться с вашей дополнительной проблемой, будучи тегами без тега, вы можете расширить предложение where до

where("(context = 'deshanatags') AND (tag_id IS NOT NULL)")
person Danny    schedule 28.03.2014
comment
Есть ли способ получить только те, у которых контекст deshanatags ? - person THpubs; 28.03.2014
comment
Через таблицу тегов есть ли способ получить список тегов, например вывод Tag.all, путем фильтрации контекста? - person THpubs; 29.03.2014
comment
EAPubs - извините за поздний ответ. Отсутствовали какое-то время - person Danny; 04.04.2014
comment
Извините, у него тоже есть проблемы. Код говорит NoMethodError: undefined method name' для nil:NilClass` - person THpubs; 07.04.2014
comment
Похоже, ваша база данных была повреждена, а теги не имеют тега... Я предлагаю очистить их, так как нет смысла держать их без дела... Альтернатива состоит в том, что вы явно игнорируете их в своем запросе, но это приводит к уродливому коду... См. последнюю строку, добавленную в решение! - person Danny; 07.04.2014
comment
Наверное удобнее начинать с tags: ActsAsTaggableOn::Tag.includes(:taggings).where('taggings.context' => :popular) - person Darkside; 19.10.2016

Я лично думаю, что оба решения будут медленными, если у вас есть много тегов для извлечения, поскольку есть много одиночных операторов выбора. Я бы сделал это так:

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'

Быстро и просто имхо

person Fabio Russo    schedule 12.08.2014
comment
Обратите внимание, что это возвращает немного другой ответ, чем исходный ответ. Теги на самом деле не дедуплицируются именами. Вместо этого вы хотите использовать: ActsAsTaggableOn::Tagging.includes(:tag).where(context: 'deshanatags').pluck(:id, :name).uniq {|id,name| name } - person Alex Moore-Niemi; 28.02.2021

Используя модель 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, который вы можете использовать.

редактировать:

Я обновил сообщение, чтобы уточнить, что делает каждый оператор, а также обновил формат нашего окончательного результата, чтобы использовать строки в качестве ключей вместо символов.

person fabianfetik    schedule 01.04.2014
comment
Это не работает... Все записи, которые я получаю от ActsAsTaggableOn::Tagging.all.where(context: "deshanatags"), выглядят так: `#‹ActsAsTaggableOn::Tagging id: 35, tag_id: 23, tagger_id: 1, tagger_type: Deshana, tagger_id: nil, tagger_type: nil, context: deshanatags , created_at: 2014-04-03 05:44:08›]` - person THpubs; 03.04.2014
comment
Да, это правильно. Вам также понадобится часть .map для получения необходимой информации. - person fabianfetik; 03.04.2014
comment
Это дает мне эту ошибку: NoMethodError: undefined method id' для nil: NilClass` - person THpubs; 07.04.2014

В более поздних версиях вы можете использовать:

ActsAsTaggableOn::Tag.for_context(:deshanatags)

Я попал сюда из Google, но потом нашел ответ в вики.

Из вики

Из кода

person davew    schedule 07.01.2020
comment
Это должен быть главный ответ сейчас! - person lunarfyre; 21.10.2020