Search code examples
ruby-on-railsrubymodel-view-controllertagsacts-as-taggable-on

How to Make Tags Persist When Updating?


The tags persist during:

  def update
    if @goal.update(goal_params)
      respond_modal_with @goal, location: root_path
    else
      render action: 'edit'
    end
  end

but when I update the goal via:

  def mark_accomplished
    @goal.update(accomplished: true)

      respond_to do |format|
        format.html
        format.js { render :nothing => true }
      end
  end

The tags for that goal then disappears when a user clicks on the mark_accomplished button:

<%= link_to 'Accomplished', mark_accomplished_path(goal), remote: true, method: 'put',  %>

The route:

get '/goal_signup/', to: 'goals#goal_signup', as: 'goal_signup'

It has something to do with the tags (gem 'acts-as-taggable-on') because this problem occurs in similar situations with my habits MVC. I'm using goals as the main example here, but let me know if you want the habits too to provide more context.

goal.rb

 class Goal < ActiveRecord::Base
    scope :publish, ->{ where(:conceal => false) }
    belongs_to :user
    acts_as_taggable
    scope :accomplished, -> { where(accomplished: true) }
    scope :unaccomplished, -> { where(accomplished: nil) }
    before_save :set_tag_owner

    def set_tag_owner
      # Set the owner of some tags based on the current tag_list
      set_owner_tag_list_on(self.user, :tags, self.tag_list)
      # Clear the list so we don't get duplicate taggings
      self.tag_list = nil
    end
end

TagsController

class TagsController < ApplicationController
  def index
    @tags = ActsAsTaggableOn::Tag.most_used(20)
    # The tags for all users and habits.
    @special_tags = ActsAsTaggableOn::Tag.includes(:taggings)
                                         .where('taggings.taggable_type' => ['Habit','User','Valuation','Goal'])
                                         .most_used(10)
    # to get tags where the current user is the tagger
    @user_tags = current_user.owned_tags
  end

  def show
    @tag = ActsAsTaggableOn::Tag.find(params[:id])
  end
end

db

  create_table "taggings", force: true do |t|
    t.integer  "tag_id"
    t.integer  "taggable_id"
    t.string   "taggable_type"
    t.integer  "tagger_id"
    t.string   "tagger_type"
    t.string   "context",       limit: 128
    t.datetime "created_at"
  end

  add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree
  add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree

  create_table "tags", force: true do |t|
    t.string  "name"
    t.integer "taggings_count", default: 0
  end

  add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree

Solution

  • Evil is before_save :set_tag_owner , you have set self.tag_list = nil. Therefore before saving Goal your tag list get emptied.

    Its working in update action because you are setting tags again.

    To solve this Issue, assign nil to tag_list only when you want to delete tags.