Как использовать jquery-Tokeninput и Acts-as-taggable-on

Так вы используете автозаполнение с jQuery Tokeninput и ActsAsTaggableOn.

В моей ситуации я использую вложенную форму, но это не имеет значения. Все ниже - это код, который работает.

код

Модель продукта:

attr_accessible :tag_list # i am using the regular :tag_list
acts_as_taggable_on :tags # Tagging products

Контроллер продуктов:

  #1. Define the tags path
  #2. Searches ActsAsTaggable::Tag Model look for :name in the created table.
  #3. it finds the tags.json path and whats on my form.
  #4. it is detecting the attribute which is :name for your tags.

def tags 
  @tags = ActsAsTaggableOn::Tag.where("tags.name LIKE ?", "%#{params[:q]}%") 
  respond_to do |format|
    format.json { render :json => @tags.map{|t| {:id => t.name, :name => t.name }}}
  end
end

Маршруты

# It has to find the tags.json or in my case /products/tags.json
get "products/tags" => "products#tags", :as => :tags

application.js:

$(function() {
  $("#product_tags").tokenInput("/products/tags.json", {
    prePopulate:       $("#product_tags").data("pre"),
    preventDuplicates: true,
    noResultsText:     "No results, needs to be created.",
    animateDropdown:   false
  });
});

форма:

<%= p.text_field :tag_list,
                 :id => "product_tags",
                 "data-pre" => @product.tags.map(&:attributes).to_json %>

Проблема 1 (РЕШЕННАЯ)


Должна иметь строку:

format.json { render :json => @tags.collect{|t| {:id => t.name, :name => t.name }}}

Примечание. Здесь вы можете использовать @tags.map, и вам также не нужно менять форму.

Ниже приведены 2 вопроса о том, почему вам нужно было сделать это:

У меня есть следующий Tag: {"id":1,"name":"Food"}. Когда я сохраняю Product, помеченный тегом "Food", он должен сохранять как ID: 1 при поиске и поиске имени "Food". В настоящее время он сохраняет новый Tag с новым идентификатором, который ссылается на идентификатор "Food", т.е. {"id":19,"name":"1"}. Вместо этого нужно найти идентификатор, показать имя и сделать find_or_create_by, чтобы он не создавал новый Tag.


Проблема 2 (РЕШЕННАЯ)


Когда я перейду к products/show, чтобы увидеть теги, выполнив <%= @product.tag_list %>. Имя появляется как " Тэги: 1", когда это действительно должно быть " Tags: Food".

Как я могу исправить эти проблемы?

Ответы

Ответ 1

Вы должны определить маршрут в routes.rb, который должен обрабатывать путь products/tags. Вы можете определить его как:

get "products/tags" => "products#tags", :as => :tags

Таким образом, вам следует предоставить помощник tags_path, который должен оцениваться как /products/tags. Это должно избавиться от ошибок, которые вы упомянули в вопросе. Не забудьте добавить этот маршрут до определения resources :product в routes.rb

Теперь на acts-as-taggable-on я не использовал этот камень, но вы должны посмотреть на метод all_tag_counts . В вашем методе ProductsController#tags понадобятся некоторые изменения в следующих строках. Я не уверен, что это именно то, что потребуется, поскольку я использую Mongoid и не могу проверить его.

def tags
  @tags = Product.all_tag_counts.(:conditions => ["#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?", "%#{params[:q]}%"])
  respond_to do |format|
    format.json { render :json => @tags.collect{|t| {:id => t.name, :name => t.name } }
  end  
end

Ответ 2

В коде Application.js есть ошибка. Существует дополнительный) после "/products/tags.json". Удалите лишние). Код должен быть:

$("#product_tags").tokenInput("/products/tags.json", {
    prePopulate:       $("#product_tags").data("pre"),
    preventDuplicates: true,
    noResultsText:     "No results, needs to be created.",
    animateDropdown:   false
});

Ответ 3

небольшое дополнение:

Если вы хотите создавать теги "на лету", вы можете сделать это в своем контроллере:

 def tags
    query = params[:q]
    if query[-1,1] == " "
      query = query.gsub(" ", "")
      Tag.find_or_create_by_name(query)
    end

    #Do the search in memory for better performance

    @tags = ActsAsTaggableOn::Tag.all
    @tags = @tags.select { |v| v.name =~ /#{query}/i }
    respond_to do |format|
      format.json{ render :json => @tags.map(&:attributes) }
    end
  end

Это создаст тэг, всякий раз, когда нажимается пробел.

Затем вы можете добавить этот параметр поиска в jquery script:

noResultsText: 'No result, hit space to create a new tag',

Это немного грязно, но это работает для меня.

Ответ 4

Я не знаю, является ли это всей вашей ошибкой, но вы не нажимаете правильный URL-адрес с помощью плагина tokenInput.

Это

$("#product_tag_list").tokenInput("/products/tags.json"), {

должен быть

$("#product_tag_list").tokenInput("/products.json"), {

Как я уже сказал, я не знаю, является ли это единственной проблемой, с которой вы сталкиваетесь, но если вы измените это, это сработает?

EDIT:

Я никогда не использовал ActsAsTaggableOn. Создает ли он модель Tag для вас?

Из взглядов на github, если вы хотите запросить все теги, вам, возможно, придется использовать свое пространство имен в отличие от просто Tag, что означает ActsAsTaggableOn::Tag. Например, вы можете увидеть, как они обращаются к Tag непосредственно в некоторых спецификациях.

Ответ 5

У меня были проблемы с редактированием тегов, если, например, модель не смогла проверить,

Я изменил

<%= p.text_field :tag_list,
             :id => "product_tags",
             "data-pre" => @product.tags.map(&:attributes).to_json %>

к

<%= p.text_field :tag_list, 
             :id => "product_tags", 
             "data-pre" => @product.tag_list.map {|tag| {:id => tag, :name => tag } }.to_json %>

Если форма не прошла проверку при первом представлении, она создавала теги как идентификатор тегов, которые она создала при последующих представлениях.

Ответ 6

Две заметки: если вы получаете теги, измененные номерами в запросе POST, используйте:

tokenValue:        "name"

И если вы пытаетесь добавить несуществующие теги, используйте (недокументированные):

allowFreeTagging:  true