2

J'ai une application RoR qui permet aux utilisateurs d'étiqueter des éléments dans leurs collections. J'utilise le plugin Jquery tag-it.js et j'utilise les appels Ajax pour ajouter et supprimer les balises dans ItemsController. Mon problème est que chaque tag est ajouté deux fois de sorte que lorsque je fais @ item.tags.each, tous les tags sont affichés deux fois.acts_as_taggable_on Tags ajoutés deux fois

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 

Javascript qui gère l'AJAX marquage avec Tag-it.js:

$('#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); 
      } 
     })   
     } 
}); 

point vue # de _form où ajoute/supprime l'utilisateur tags:

<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/<%[email protected] %>/items/autocomplete_tag_name"> 
     <% @item.tags.each do |tag| %> 
     <li><%= tag.name %></li>    
     <% end %>     
</ul> 

Je dois noter qu'il est nécessaire d'avoir une propriété de balise (par current_user) pour que l'achèvement automatique de Jquery se termine uniquement en fonction des balises précédentes de l'utilisateur actuel et pas de tous les utilisateurs. Je pense que le problème est que je dois ajouter la balise à la tag_list, puis ajouter la tag_list au marquage des éléments utilisateur. Je ne peux pas trouver un moyen de contourner cela parce que la méthode current_user.tag() semble remplacer les balises d'élément précédent lorsque current_user.tag() est appelé, donc je dois ajouter la nouvelle balise aux balises précédentes pour les conserver. En outre, lorsque je soumets l'élément # _form, la méthode de mise à jour doit ignorer l'attribut tags car il tente de les enregistrer dans l'élément, mais ils sont déjà enregistrés avec un appel AJAX, ce qui me donne l'erreur suivante:

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

Merci d'avance.

PS. Voici comment je suis arrivé l'auto travail complet dans le ItemsController:

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

Hum ... mon problème a commencé quand j'ajouté 'profile.tag_list.add ("bob")' à mon code de contrôleur, que vous avez. Je pense que cette ligne est inutile. Sans cela, je reçois juste une étiquette. Avec cela, j'ai des doublons. – Ziggy

Répondre

0

Faites attention à l'événement onTagAdded tiré sur la charge de page. Voir l'exemple d'événements ici 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)); 
}); 
0

Vous aviez raison:

I think the problem is that I have to add the tag to the tag_list and then add the tag_list to the user item tagging. I can't find a way around this because the current_user.tag() method seems to overwrite the previous item tags when current_user.tag() is called so I have to add the new tag to the previous tags to preserve them.

La méthode .tag sur-écrit les balises existantes avec la liste donnée. Donc, si vous voulez ajouter de nouvelles balises, il semble que vous deviez ajouter vos nouvelles balises aux balises existantes, puis transmettre cette nouvelle liste. Cependant, .tag_list.add crée également des étiquettes.

Alors, quand vous faites ceci:

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

Vous étiez en effet d'ajouter la nouvelle étiquette deux fois.

Et quand je faisais ceci:

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

je créais une référence à la liste_balise, puis en appelant ajouter là-dessus. Ce que nous devions faire était ceci:

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

Pour créer un tableau des noms de variables pour l'objet que nous étiquetons.Ensuite, nous pouvons appeler ajouter sur la copie de la liste, pas de problème! Plus de tags en double. Je suis content d'avoir rencontré votre question, car elle m'a conduit à une réponse qui a fonctionné pour moi. Cependant, je serais encore plus heureux s'il y avait juste une belle façon de faire cela fourni par la bibliothèque. Je n'ai pas réussi à trouver un bon moyen juste en lisant les docs.

+0

Ha ha, non, cela écrase toujours les balises existantes ... attends je travaille dessus! – Ziggy

+0

OK maintenant ça marche. – Ziggy

0

Vous alliez bien, mais juste une petite erreur.

Ici tag_list est d'obtenir des balises en double, l'un avec propriétaire et d'autres sans propriétaire

Votre ligne @item.tag_list.add(params[:tag]) ajoute des balises sans ligne Propriétaire

Et current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags) ajoute même tag avec le propriétaire

Et plus tard, lorsque vous enregistrez l'objet, depuis tag_list se comporte comme référence à non-propriétaire étiquettes de l'objet, les deux sont enregistrés

Le code suivant doit fonctionner correctement.

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 

improved version

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 
Questions connexes