【问题标题】:acts_as_taggable_on Tags added twiceact_as_taggable_on 标签添加了两次
【发布时间】:2012-05-30 07:15:53
【问题描述】:

我有一个 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="<%= 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() 时覆盖了以前的项目标签,所以我必须将新标签添加到以前的标签中以保留它们。

此外,当我提交 item#_form 时,我需要以某种方式让 update 方法忽略 tags 属性,因为它试图将它们保存到 item 但它们已经通过 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

【问题讨论】:

  • 嗯...当我将profile.tag_list.add("bob") 添加到我的控制器代码时,我的问题就开始了,就像你一样。我认为那条线是不必要的。没有它,我只会得到一个标签。有了它,我得到了重复。

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


【解决方案1】:

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

这里tag_list 得到重复的标签,一个有Owner,另一个没有Owner

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

并且current_user.tag(@item, :with =&gt; @item.tag_list.to_s, :on =&gt; :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】:

    你是对的:

    我认为问题在于我必须将标签添加到 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 了,没问题!不再有重复的标签。

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

    【讨论】:

    • 哈哈,不,这仍然会覆盖现有标签...等等,我正在处理它!
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2012-09-05
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-07
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多