diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index b65d54ae0c9..a0bb276fde0 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -25,51 +25,34 @@ class TagsController < ::ApplicationController respond_to do |format| format.html do - tag_counts = self.class.tags_by_count(guardian, limit: 300).count(Tag::COUNT_ARG) - @tags = self.class.tag_counts_json(tag_counts) render :index end format.json do if SiteSetting.tags_listed_by_group - # TODO: performance is bad - grouped_tag_counts = TagGroup.order('name ASC').preload(:tags).map do |tag_group| - h = Tag.tags_by_count_query(limit: 300) - .joins("LEFT JOIN tag_group_memberships ON tags.id = tag_group_memberships.tag_id") - .where('tag_group_memberships.tag_group_id = ?', tag_group.id) - .count(Tag::COUNT_ARG) - { id: tag_group.id, name: tag_group.name, tags: self.class.tag_counts_json(h) } + grouped_tag_counts = TagGroup.order('name ASC').includes(:tags).map do |tag_group| + { id: tag_group.id, name: tag_group.name, tags: self.class.tag_counts_json(tag_group.tags) } end - ungrouped_tag_counts = guardian.filter_allowed_categories( - Tag.tags_by_count_query(limit: 300) - .where("tags.id NOT IN (select tag_id from tag_group_memberships)") - .count(Tag::COUNT_ARG) - ) + ungrouped_tags = Tag.where("tags.id NOT IN (select tag_id from tag_group_memberships)") render json: { - tags: self.class.tag_counts_json(ungrouped_tag_counts), # tags that don't belong to a group + tags: self.class.tag_counts_json(ungrouped_tags), # tags that don't belong to a group extras: { tag_groups: grouped_tag_counts } } else - unrestricted_tag_counts = guardian.filter_allowed_categories( - Tag.tags_by_count_query(limit: 300) - .where("tags.id NOT IN (select tag_id from category_tags)") - .count(Tag::COUNT_ARG) - ) + unrestricted_tags = Tag.where("tags.id NOT IN (select tag_id from category_tags)") categories = Category.where("id in (select category_id from category_tags)") .where("id in (?)", guardian.allowed_category_ids) - .preload(:tags) + .includes(:tags) category_tag_counts = categories.map do |c| - h = Tag.category_tags_by_count_query(c, limit: 300).count(Tag::COUNT_ARG) - h.merge!(c.tags.where.not(name: h.keys).inject({}) { |sum, t| sum[t.name] = 0; sum }) # unused tags - { id: c.id, tags: self.class.tag_counts_json(h) } + { id: c.id, tags: self.class.tag_counts_json(c.tags) } end render json: { - tags: self.class.tag_counts_json(unrestricted_tag_counts), + tags: self.class.tag_counts_json(unrestricted_tags), extras: { categories: category_tag_counts } } end @@ -160,7 +143,7 @@ class TagsController < ::ApplicationController category = params[:categoryId] ? Category.find_by_id(params[:categoryId]) : nil tags_with_counts = DiscourseTagging.filter_allowed_tags( - Tag.tags_by_count_query(params.slice(:limit)), + Tag.order('topic_count DESC').limit(params[:limit]), guardian, for_input: params[:filterForInput], term: params[:q], @@ -168,7 +151,7 @@ class TagsController < ::ApplicationController selected_tags: params[:selected_tags] ) - tags = tags_with_counts.count(Tag::COUNT_ARG).map { |t, c| { id: t, text: t, count: c } } + tags = self.class.tag_counts_json(tags_with_counts) json_response = { results: tags } @@ -211,12 +194,8 @@ class TagsController < ::ApplicationController raise Discourse::NotFound unless SiteSetting.tagging_enabled? end - def self.tags_by_count(guardian, opts = {}) - guardian.filter_allowed_categories(Tag.tags_by_count_query(opts)) - end - - def self.tag_counts_json(tag_counts) - tag_counts.map { |t, c| { id: t, text: t, count: c } } + def self.tag_counts_json(tags) + tags.map { |t| { id: t.name, text: t.name, count: t.topic_count } } end def set_category_from_params diff --git a/app/jobs/scheduled/ensure_db_consistency.rb b/app/jobs/scheduled/ensure_db_consistency.rb index c86e5c31996..a4826316214 100644 --- a/app/jobs/scheduled/ensure_db_consistency.rb +++ b/app/jobs/scheduled/ensure_db_consistency.rb @@ -15,6 +15,7 @@ module Jobs Badge.ensure_consistency! CategoryUser.ensure_consistency! UserOption.ensure_consistency! + Tag.ensure_consistency! end end end diff --git a/app/models/tag.rb b/app/models/tag.rb index 7d5b4f4139a..2e8a2c66944 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -31,9 +31,24 @@ class Tag < ActiveRecord::Base q end - def self.category_tags_by_count_query(category, opts = {}) - tags_by_count_query(opts).where("tags.id in (select tag_id from category_tags where category_id = ?)", category.id) - .where("topics.category_id = ?", category.id) + def self.ensure_consistency! + update_topic_counts # topic_count counter cache can miscount + end + + def self.update_topic_counts + Category.exec_sql <<~SQL + UPDATE tags t + SET topic_count = x.topic_count + FROM ( + SELECT COUNT(topics.id) AS topic_count, tags.id AS tag_id + FROM tags + LEFT JOIN topic_tags ON tags.id = topic_tags.tag_id + LEFT JOIN topics ON topics.id = topic_tags.topic_id AND topics.deleted_at IS NULL + GROUP BY tags.id + ) x + WHERE x.tag_id = t.id + AND x.topic_count <> t.topic_count + SQL end def self.top_tags(limit_arg: nil, category: nil, guardian: nil) diff --git a/app/views/tags/index.html.erb b/app/views/tags/index.html.erb index 41f18eeb7b7..cc250d46849 100644 --- a/app/views/tags/index.html.erb +++ b/app/views/tags/index.html.erb @@ -1,24 +1,3 @@ -<% if crawler_layout? %> - -<% content_for :title do %><%=t "tags.title" %> - <%= SiteSetting.title %><% end %> - -