app/models/post/tag_methods.rb
# Commit any tag changes to the database.  This is done after save, so any changes
# must be made directly to the database.
Commit any tag changes to the database.  This is done after save, so any changes
must be made directly to the database.
Commit any tag changes to the database . This is done after save so any changes must be made directly to the database .
def commit_tags
    return if new_tags.nil?
    if old_tags
      current_tags = cached_tags.scan(/\S+/)
      self.old_tags = Tag.scan_tags(old_tags)
      self.new_tags = (current_tags + new_tags) - old_tags + (current_tags & new_tags)
    end
    metatags, self.new_tags = new_tags.partition { |x| x =~ /^((?:-pool|pool|rating|parent|child):|[qse]$)/ }
    transaction do
      metatags.each do |metatag|
        if metatag =~ /^([qse])$/
          metatag = "rating:{Regexp.last_match[1]}"
        end
        case metatag
        when /^pool:(.+)/
          begin
            name, seq = Regexp.last_match[1].split(":")
            pool = Pool.find_by_name(name)
            options = { :user => User.find(updater_user_id), :ignore_already_exists => true }
            if defined?(seq)
              options[:sequence] = seq
            end
            if pool.nil? && name !~ /^\d+$/
              pool = Pool.create(:name => name, :is_public => false, :user_id => updater_user_id)
            end
            next if pool.nil?
            next if Thread.current["danbooru-user"] && !pool.can_change?(Thread.current["danbooru-user"], nil)
            pool.add_post(id, options) if pool
          rescue Pool::PostAlreadyExistsError
          rescue Pool::AccessDeniedError
          end
        when /^-pool:(.+)/
          name, cmd = Regexp.last_match[1].split(":")
          pool = Pool.find_by_name(name)
          next if Thread.current["danbooru-user"] && !pool.can_change?(Thread.current["danbooru-user"], nil)
          if cmd == "parent"
            unless parent_id.nil?
              pool.transfer_post_to_parent(id, parent_id)
            end
            next
          end
          pool.remove_post(id) if pool
        when /^rating:([qse])/
          self.rating = Regexp.last_match[1] 
          execute_sql("UPDATE posts SET rating = ? WHERE id = ?", Regexp.last_match[1], id)
        when /^parent:(\d*)/
          self.parent_id = Regexp.last_match[1]
          if Post.exists?(parent_id) || parent_id == 0
            Post.set_parent(id, parent_id)
          end
        when /^child:(\d*)/
          child_id = Regexp.last_match[1]
          if Post.exists?(child_id)
            p = Post.find(child_id)
            p.parent_id = id
            p.save!
          end
        end
      end
      new_tags << "tagme" if new_tags.empty?
      self.new_tags = TagAlias.to_aliased(new_tags)
      self.new_tags = TagImplication.with_implied(new_tags).uniq
      execute_sql("DELETE FROM posts_tags WHERE post_id = ?", id)
      self.new_tags = new_tags.map { |x| Tag.find_or_create_by_name(x) }.uniq
      unless new_tags.empty?
        any_new_tags = false
        previous_tags = cached_tags.split(" ")
        new_tags.each do |tag|
          if tag.post_count == 0 && !previous_tags.include?(tag.name)
            any_new_tags = true
          end
        end
        if any_new_tags
          Moebooru::CacheHelper.increment_version("tag")
        end
      end
       Work around this by selecting the existing tags within the INSERT and removing
       any that already exist.  Normally, the inner SELECT will return no rows; if
       another process inserts rows before our INSERT, it'll return the rows that it
       inserted and we'll avoid duplicating them.
      tag_set = new_tags.map { |x| ("({id}, {x.id})") }.join(", ")
       execute_sql("INSERT INTO posts_tags (post_id, tag_id) VALUES " + tag_set)
      sql = <<-EOS
        INSERT INTO posts_tags (post_id, tag_id)
        SELECT t.post_id, t.tag_id
         FROM (VALUES {tag_set}) AS t(post_id, tag_id)
         WHERE t.tag_id NOT IN (SELECT tag_id FROM posts_tags pt WHERE pt.post_id = {id})
      EOS
      execute_sql(sql)
      Post.recalculate_cached_tags(id)
       Store the old cached_tags, so we can expire them.
      self.old_cached_tags = cached_tags
      self.cached_tags = select_value_sql("SELECT cached_tags FROM posts WHERE id = {id}")
      self.new_tags = nil
    end
  end
def commit_tags return if new_tags . nil? if old_tags current_tags = cached_tags . scan ( / \S + / ) self . old_tags = Tag . scan_tags ( old_tags ) self . new_tags = ( current_tags + new_tags ) - old_tags + ( current_tags & new_tags ) end metatags , self . new_tags = new_tags . partition { | x | x =~ / ^((?:-pool|pool|rating|parent|child):|[qse]$) / } transaction do metatags . each do | metatag | if metatag =~ / ^([qse])$ / metatag = "rating:#{Regexp.last_match[1]}" end case metatag when / ^pool:(.+) / begin name , seq = Regexp . last_match [ 1 ] . split ( ":" ) pool = Pool . find_by_name ( name ) options = { :user => User . find ( updater_user_id ) , :ignore_already_exists => true } if defined? ( seq ) options [ :sequence ] = seq end if pool . nil? && name !~ / ^ \d +$ / pool = Pool . create ( :name => name , :is_public => false , :user_id => updater_user_id ) end next if pool . nil? next if Thread . current [ "danbooru-user" ] && ! pool . can_change? ( Thread . current [ "danbooru-user" ] , nil ) pool . add_post ( id , options ) if pool rescue Pool :: PostAlreadyExistsError rescue Pool :: AccessDeniedError end when / ^-pool:(.+) / name , cmd = Regexp . last_match [ 1 ] . split ( ":" ) pool = Pool . find_by_name ( name ) next if Thread . current [ "danbooru-user" ] && ! pool . can_change? ( Thread . current [ "danbooru-user" ] , nil ) if cmd == "parent" unless parent_id . nil? pool . transfer_post_to_parent ( id , parent_id ) end next end pool . remove_post ( id ) if pool when / ^rating:([qse]) / self . rating = Regexp . last_match [ 1 ] execute_sql ( "UPDATE posts SET rating = ? WHERE id = ?" , Regexp . last_match [ 1 ] , id ) when / ^parent:( \d *) / self . parent_id = Regexp . last_match [ 1 ] if Post . exists? ( parent_id ) || parent_id == 0 Post . set_parent ( id , parent_id ) end when / ^child:( \d *) / child_id = Regexp . last_match [ 1 ] if Post . exists? ( child_id ) p = Post . find ( child_id ) p . parent_id = id p . save! end end end new_tags << "tagme" if new_tags . empty? self . new_tags = TagAlias . to_aliased ( new_tags ) self . new_tags = TagImplication . with_implied ( new_tags ) . uniq execute_sql ( "DELETE FROM posts_tags WHERE post_id = ?" , id ) self . new_tags = new_tags . map { | x | Tag . find_or_create_by_name ( x ) } . uniq unless new_tags . empty? any_new_tags = false previous_tags = cached_tags . split ( " " ) new_tags . each do | tag | if tag . post_count == 0 && ! previous_tags . include? ( tag . name ) any_new_tags = true end end if any_new_tags Moebooru :: CacheHelper . increment_version ( "tag" ) end end tag_set = new_tags . map { | x | ( "(#{id}, #{x.id})" ) } . join ( ", " ) sql = <<-EOS 
        INSERT INTO posts_tags (post_id, tag_id)
        SELECT t.post_id, t.tag_id
         FROM (VALUES  #{ tag_set } ) AS t(post_id, tag_id)
         WHERE t.tag_id NOT IN (SELECT tag_id FROM posts_tags pt WHERE pt.post_id =  #{ id } )
       EOS execute_sql ( sql ) Post . recalculate_cached_tags ( id ) self . old_cached_tags = cached_tags self . cached_tags = select_value_sql ( "SELECT cached_tags FROM posts WHERE id = #{id}" ) self . new_tags = nil end end
Commit any tag changes to the database.
Commit any tag changes to the database .
# If someone else committed changes to this post before we did, # then try to merge the tag changes together. # Set :ignore_already_exists, so pool:1:2 can be used to change the sequence number # of a post that already exists in the pool. # If we have a parent, remove ourself from the pool and add our parent in # our place.  If we have no parent, do nothing and leave us in the pool. # so we don't have to reload for history_tag_string below # Don't just use set_parent, or history won't be saved, since it saves directly # to the database. # TODO: be more selective in deleting from the join table # If any tags are newly active, expire the tag cache. # If this tag is in old_tags, then it's already active and we just removed it # in the above DELETE, so it's not really a newly activated tag.  (This isn't # self.old_tags; that's the tags the user saw before he edited, not the data # we're replacing.) # Tricky: Postgresql's locking won't serialize this DELETE/INSERT, so it's # possible for two simultaneous updates to both delete all tags, then insert # them, duplicating them all. # # Work around this by selecting the existing tags within the INSERT and removing # any that already exist.  Normally, the inner SELECT will return no rows; if # another process inserts rows before our INSERT, it'll return the rows that it # inserted and we'll avoid duplicating them. # execute_sql("INSERT INTO posts_tags (post_id, tag_id) VALUES " + tag_set) # Store the old cached_tags, so we can expire them.