Search code examples
ruby-on-railstaggingacts-as-taggable-on

Tag an object N times with same tag using acts_as_taggable_on


I'm using acts_as_taggable_on, but now have a new requirement:

The end goal: Users should be able to agree with the tag choice another user has made, making the tagging more credible / reliable.

I see two ways to do this:

1) One way to do this would be to let an object be tagged more than once with the same tag (ie, tag_id doesn't need to be unique within the tagging context).

I know how to remove the validation in tagging.rb, but how do I change the code to let multiple users tag an object with the same tag? Is it as simple as removing the validation?

2.) Another way would be to make taggings voteable using thumbs_up, so users can upvote / downvote the tagging decision.

Both of these seem weak, so I'm leaning towards rolling my own tagging solution, but I'd rather DRY – so, any insights into which method is best, or am I missing some easy way to do this?


Solution

  • The acts_as_taggable_on gem supports this use case, actually. The key is using the tag ownership features:

    @owner_a.tag(@taggable_object, :with => "list,of,tags", :on => :taggable_attribute)
    @owner_b.tag(@taggable_object, :with => "list,of,neat,tags", :on => :taggable_attribute)
    
    @taggable_object.taggable_attribute(@some_user, :locations) # => [#<ActsAsTaggableOn::Tag id: 1, name: "list">...]
    

    This will give you a list of all tags, including duplicate tags from unique owners, effectively allowing each user to tag an object with a specific tag one time.

    I use the following to convert that list to a hash of unique tags with a count for each tag:

    @taggable_object.taggable_attribute.inject(Hash.new(0)) {|h,i| h[i.name] += 1; h } # => { "list" => 2, ... "neat" => 1 }
    

    I use this to see which tags the user has already applied to the object, which lets me determine with to show a down/upvote icon:

    @taggable_object.owner_tags_on(@owner_1, :taggable_attribute); # => [#<ActsAsTaggableOn::Tag id: 1, name: "list">...]
    

    Remember that acts as taggable on always overwrites the previous tag list when using the ownership feature, so adding another @owner_a.tag(:taggable_object, :with => "new,tags"...) would erase the previously tagged items on the @taggable_object.