acts_as_taggable_on标签已添加两次

我有一个RoR应用程序,允许用户标记其集合中的项目。 我使用tag-it.js Jquery插件并使用Ajax调用来添加和删除ItemsController中的标签。 我的问题是每个标记都添加了两次,这样当我执行@ item.tags.each时,所有标记都会显示两次。

上述ItemsController:

def add_tag @collection = current_user.collections.find(params[:collection_id]) @item = @collection.items.find(params[:id]) @item.tag_list.add(params[:tag]) current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags) @item.save render nothing: true end def remove_tag @item = current_user.items.find_by_id(params[:id]) @item.tag_list.remove(params[:tag]) current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags) @item.save render nothing: true end 

使用Tag-it.js处理AJAX标记的Javascript:

 $('#item_tags').tagit({ onTagAdded: function(event, tag) { var add_url = $('#item_tags').attr("data-add-url"); $.ajax({ url: add_url, data: {tag: tag.text().substring(0, tag.text().length-1)}, }) }, onTagRemoved: function(event, tag) { var remove_url = $('#item_tags').attr("data-remove-url"); $.ajax({ url: remove_url, type: 'DELETE', data: {tag: tag.text().substring(0, tag.text().length-1)}, }) }, tagSource: function(search, showChoices) { var autocomplete_url = $('#item_tags').attr("data-auctocomplete-url"); $.ajax({ url: autocomplete_url, data: {term: search.term}, success: function(choices) { showChoices(choices); } }) } }); 

item#_form视图用户添加/删除标签的位置:

 <ul id='item_tags' class='tagit' data-remove-url="" data-add-url="" data-auctocomplete-url="/collections//items/autocomplete_tag_name">  
  • 我必须注意,必须拥有标签所有权(通过current_user),以便Jquery自动完成仅基于当前用户以前的标签而不是所有用户完成。 我认为问题是我必须将标记添加到tag_list,然后将tag_list添加到用户项标记。 我无法找到解决方法,因为当调用current_user.tag()时,current_user.tag()方法似乎会覆盖以前的项目标记,因此我必须将新标记添加到以前的标记以保留它们。

    另外,当我提交项目#_form时,我需要以某种方式让更新方法忽略tags属性,因为它试图将它们保存到项目中,但它们已经通过AJAX调用保存,所以我收到此错误:

     ActiveRecord::AssociationTypeMismatch in ItemsController#update ActsAsTaggableOn::Tag(#82082080) expected, got String(#72294010) 

    提前致谢。

    PS。 以下是我在ItemsController中完成自动完成工作的方法:

     def get_autocomplete_items(parameters) tags = current_user.owned_tags.named_like(parameters[:term]) end 

    你是对的:

    我认为问题是我必须将标记添加到tag_list,然后将tag_list添加到用户项标记。 我无法找到解决方法,因为当调用current_user.tag()时,current_user.tag()方法似乎会覆盖以前的项目标记,因此我必须将新标记添加到以前的标记以保留它们。

    .tag方法使用给定列表覆盖现有标记。 因此,如果您想添加新标签,您似乎需要将新标签附加到现有标签,然后传入新列表。 但是, .tag_list.add实际上也会创建标记。

    所以,当你这样做时:

      @item.tag_list.add(params[:tag]) current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags) 

    你确实两次添加新标签。

    当我这样做时:

     tag_list = profile.tag_list // oops! tag_list.add(tags) self.tag(profile, with: tag_list, on: :tags) 

    我正在创建对tag_list的引用,然后在其上调用add。 我们需要做的是:

     tag_list = profile.tags.map(&:name) 

    为我们标记的对象创建一个标记名称数组。 然后我们可以在列表的副本上调用add,没问题! 没有更多重复的标签。

    我很高兴遇到了你的问题,因为它让我得到了一个对我有用的答案。 但是,如果图书馆提供的这种方式很好,我会更高兴。 通过阅读文档,我无法找到一个好方法。

    你做得很好,但是,只是一个小错误。

    这里tag_list获取重复的标签,一个拥有所有者 ,另一个没有所有者

    你的@item.tag_list.add(params[:tag])行正在添加没有所有者的标签

    current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags)行正在添加相同的标签

    之后,当您保存对象时,由于tag_list表现为对象的无标记标记的引用,因此都会保存

    以下代码应正常工作。

      def add_tag @collection = current_user.collections.find(params[:collection_id]) @item = @collection.items.find(params[:id]) tag_list = @item.all_tag_list.dup # Reference to original tag_list avoided # Also instead of "tag_list", use "all_tag_list" method, as "tag_list" only return tags without owner # Link(go to last line og Tag Ownership topic) : "https://github.com/mbleigh/acts-as-taggable-on#tag-ownership" tag_list.add(params[:tag]) current_user.tag(@item, :with => tag_list.to_s, :on => :tags) @item.save render nothing: true end def remove_tag @item = current_user.items.find_by_id(params[:id]) tag_list = @item.all_tag_list.dup # Reference to original tag_list avoided tag_list.remove(params[:tag]) current_user.tag(@item, :with => tag_list.to_s, :on => :tags) @item.save render nothing: true end 

    改良版

     def add_owned_tag @some_item = Item.find(params[:id]) owned_tag_list = @some_item.all_tag_list - @some_item.tag_list owned_tag_list += [(params[:tag])] @tag_owner.tag(@some_item, :with => stringify(owned_tag_list), :on => :tags) @some_item.save end def stringify(tag_list) tag_list.inject('') { |memo, tag| memo += (tag + ',') }[0..-1] end def remove_owned_tag @some_item = Item.find(params[:id]) owned_tag_list = @some_item.all_tag_list - @some_item.tag_list owned_tag_list -= [(params[:tag])] @tag_owner.tag(@some_item, :with => stringify(owned_tag_list), :on => :tags) @some_item.save end 

    注意在页面加载时触发的onTagAdded事件。 请参阅此处的事件示例http://aehlke.github.com/tag-it/examples.html

     //------------------------------- // Tag events //------------------------------- var eventTags = $('#eventTags'); eventTags.tagit({ availableTags: sampleTags, onTagRemoved: function(evt, tag) { console.log(evt); alert('This tag is being removed: ' + eventTags.tagit('tagLabel', tag)); }, onTagClicked: function(evt, tag) { console.log(tag); alert('This tag was clicked: ' + eventTags.tagit('tagLabel', tag)); } }).tagit('option', 'onTagAdded', function(evt, tag) { // Add this callbackafter we initialize the widget, // so that onTagAdded doesn't get called on page load. alert('This tag is being added: ' + eventTags.tagit('tagLabel', tag)); });