acts_as_taggable_on标签已添加两次

时间:2012-05-23 17:34:31

标签: ruby-on-rails ruby-on-rails-3 tags acts-as-taggable-on tag-it

我有一个允许用户标记其馆藏中的项目的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);
          }
        })           
      }
});

项目#_form查看用户添加/删除标记的位置:

<ul id='item_tags' class='tagit' data-remove-url="<%= remove_tag_collection_item_path %>" data-add-url="<%= add_tag_collection_item_path %>" data-auctocomplete-url="/collections/<%=@collection.id %>/items/autocomplete_tag_name"> 
      <% @item.tags.each do |tag| %>   
        <li><%= tag.name %></li>            
      <% end %>                   
</ul>

我必须注意,必须拥有标签所有权(通过current_user),以便Jquery自动完成仅基于当前用户以前的标签而不是所有用户完成。我认为问题是我必须将标记添加到tag_list,然后将tag_list添加到用户项标记。我无法找到解决方法,因为当调用current_user.tag()时,current_user.tag()方法似乎会覆盖先前的项目标记,因此我必须将新标记添加到以前的标记以保留它们。

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

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

3 个答案:

答案 0 :(得分:0)

你是对的:

  

我认为问题是我必须将标签添加到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,没问题!没有更多重复的标签。

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

答案 1 :(得分:0)

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

此处tag_list获取重复标记,其中一个包含所有者,其他包含所有者

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

并且current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags)行正在添加相同的标记与所有者

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

以下代码可以正常工作。

  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

答案 2 :(得分:-1)

注意在页面加载时触发的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));
 });