TagSetPresenter: refactor *_tag_list_html to avoid memcache calls.

Refactor the tag set presenter to get both the tag categories and the
tag counts in the same call to the database, instead of getting the
counts from the db and the categories from memcache.
This commit is contained in:
evazion
2018-09-30 13:21:12 -05:00
parent 99632d5e8a
commit b1f2096d72
2 changed files with 38 additions and 45 deletions

View File

@@ -56,10 +56,6 @@ class Tag < ApplicationRecord
extend ActiveSupport::Concern extend ActiveSupport::Concern
module ClassMethods module ClassMethods
def counts_for(tag_names)
select_all_sql("SELECT name, post_count FROM tags WHERE name IN (?)", tag_names)
end
def highest_post_count def highest_post_count
Cache.get("highest-post-count", 4.hours) do Cache.get("highest-post-count", 4.hours) do
select("post_count").order("post_count DESC").first.post_count select("post_count").order("post_count DESC").first.post_count

View File

@@ -5,7 +5,8 @@
=end =end
class TagSetPresenter < Presenter class TagSetPresenter < Presenter
attr_reader :tag_names, :tags extend Memoist
attr_reader :tag_names
def initialize(tag_names) def initialize(tag_names)
@tag_names = tag_names @tag_names = tag_names
@@ -13,9 +14,10 @@ class TagSetPresenter < Presenter
def tag_list_html(current_query: "", show_extra_links: false, name_only: false) def tag_list_html(current_query: "", show_extra_links: false, name_only: false)
html = "" html = ""
if tag_names.present?
if ordered_tags.present?
html << '<ul itemscope itemtype="http://schema.org/ImageObject">' html << '<ul itemscope itemtype="http://schema.org/ImageObject">'
tag_names.each do |tag| ordered_tags.each do |tag|
html << build_list_item(tag, current_query: current_query, show_extra_links: show_extra_links, name_only: name_only) html << build_list_item(tag, current_query: current_query, show_extra_links: show_extra_links, name_only: name_only)
end end
html << "</ul>" html << "</ul>"
@@ -28,7 +30,8 @@ class TagSetPresenter < Presenter
html = "" html = ""
category_list.each do |category| category_list.each do |category|
typetags = typed_tags(category) typetags = ordered_tags.select { |tag| tag.category == Tag.categories.value_for(category) }
if typetags.any? if typetags.any?
html << TagCategory.header_mapping[category] if headers html << TagCategory.header_mapping[category] if headers
html << %{<ul class="#{category}-tag-list">} html << %{<ul class="#{category}-tag-list">}
@@ -50,60 +53,54 @@ class TagSetPresenter < Presenter
private private
def typed_tags(name) def tags
@typed_tags ||= {} Tag.where(name: tag_names).select(:name, :post_count, :category)
@typed_tags[name] ||= begin end
tag_names.select do |tag| memoize :tags
categories[tag] == TagCategory.mapping[name]
end def ordered_tags
end names_to_tags = tags.map { |tag| [tag.name, tag] }.to_h
end
tag_names.map do |name|
def categories names_to_tags[name] || Tag.new(name: name).freeze
@categories ||= Tag.categories_for(tag_names)
end
def counts
@counts ||= Tag.counts_for(tag_names).inject({}) do |hash, x|
hash[x["name"]] = x["post_count"]
hash
end end
end end
memoize :ordered_tags
def build_list_item(tag, name_only: false, humanize_tags: true, show_extra_links: false, current_query: "") def build_list_item(tag, name_only: false, humanize_tags: true, show_extra_links: false, current_query: "")
html = %{<li class="category-#{categories[tag]}">} name = tag.name
count = tag.post_count
category = tag.category
html = %{<li class="category-#{tag.category}">}
unless name_only unless name_only
if categories[tag] == Tag.categories.artist if category == Tag.categories.artist
html << %{<a class="wiki-link" href="/artists/show_or_new?name=#{u(tag)}">?</a> } html << %{<a class="wiki-link" href="/artists/show_or_new?name=#{u(name)}">?</a> }
else else
html << %{<a class="wiki-link" href="/wiki_pages/show_or_new?title=#{u(tag)}">?</a> } html << %{<a class="wiki-link" href="/wiki_pages/show_or_new?title=#{u(name)}">?</a> }
end end
if show_extra_links && current_query.present? if show_extra_links && current_query.present?
html << %{<a rel="nofollow" href="/posts?tags=#{u(current_query)}+#{u(tag)}" class="search-inc-tag">+</a> } html << %{<a rel="nofollow" href="/posts?tags=#{u(current_query)}+#{u(name)}" class="search-inc-tag">+</a> }
html << %{<a rel="nofollow" href="/posts?tags=#{u(current_query)}+-#{u(tag)}" class="search-exl-tag">&ndash;</a> } html << %{<a rel="nofollow" href="/posts?tags=#{u(current_query)}+-#{u(name)}" class="search-exl-tag">&ndash;</a> }
end end
end end
humanized_tag = humanize_tags ? tag.tr("_", " ") : tag humanized_tag = humanize_tags ? name.tr("_", " ") : name
if categories[tag] == Tag.categories.artist itemprop = 'itemprop="author"' if category == Tag.categories.artist
itemprop = 'itemprop="author"' html << %{<a class="search-tag" #{itemprop} href="/posts?tags=#{u(name)}">#{h(humanized_tag)}</a> }
else
itemprop = nil
end
html << %{<a class="search-tag" #{itemprop} href="/posts?tags=#{u(tag)}">#{h(humanized_tag)}</a> }
unless name_only unless name_only || tag.new_record?
if counts[tag].to_i >= 10_000 if count >= 10_000
post_count = "#{counts[tag].to_i / 1_000}k" post_count = "#{count / 1_000}k"
elsif counts[tag].to_i >= 1_000 elsif count >= 1_000
post_count = "%.1fk" % (counts[tag].to_f / 1_000) post_count = "%.1fk" % (count / 1_000.0)
else else
post_count = counts[tag].to_s post_count = count
end end
is_underused_tag = counts[tag].to_i <= 1 && categories[tag] == Tag.categories.general is_underused_tag = count <= 1 && category == Tag.categories.general
klass = "post-count#{is_underused_tag ? " low-post-count" : ""}" klass = "post-count#{is_underused_tag ? " low-post-count" : ""}"
title = "New general tag detected. Check the spelling or populate it now." title = "New general tag detected. Check the spelling or populate it now."