add some caching and preloading to user show page
This commit is contained in:
@@ -12,6 +12,26 @@ module Domain::Fa::UsersHelper
|
||||
end
|
||||
|
||||
def sanitized_fa_user_profile_html(html)
|
||||
# try to preload all the FA usernames in the profile
|
||||
maybe_url_names = Nokogiri::HTML(html).css("a").flat_map do |node|
|
||||
href = URI.parse(node["href"])
|
||||
right_host = href.host.nil? || href.host == "www.furaffinity.net"
|
||||
right_path = href.path =~ /\/user\/.+/
|
||||
if right_host && right_path
|
||||
[href]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end.map do |href|
|
||||
href.path.split("/")[2]&.downcase
|
||||
end
|
||||
|
||||
preloaded_users = Domain::Fa::User.
|
||||
where(url_name: maybe_url_names).
|
||||
select(:state, :state_detail, :log_entry_detail, :url_name).
|
||||
includes(:avatar).
|
||||
index_by(&:url_name)
|
||||
|
||||
raw Sanitize.fragment(
|
||||
html,
|
||||
elements: %w[br img b i span strong],
|
||||
@@ -28,7 +48,7 @@ module Domain::Fa::UsersHelper
|
||||
href = URI.parse(node["href"])
|
||||
return unless href.host == nil || href.host == "www.furaffinity.net"
|
||||
return unless href.path =~ /\/user\/.+/
|
||||
url_name = href.path.split("/")[2]
|
||||
url_name = href.path.split("/")[2]&.downcase
|
||||
Sanitize.node!(node, {
|
||||
:elements => %w[a],
|
||||
:attributes => {
|
||||
@@ -42,7 +62,8 @@ module Domain::Fa::UsersHelper
|
||||
|
||||
whitelist = [node]
|
||||
|
||||
if (user = Domain::Fa::User.find_by(url_name: url_name))
|
||||
user = preloaded_users[url_name] || Domain::Fa::User.find_by(url_name: url_name)
|
||||
if user
|
||||
img = Nokogiri::XML::Node.new("img", node.document)
|
||||
img["class"] = "inline w-5"
|
||||
img["src"] = fa_user_avatar_path(user, thumb: "32-avatar")
|
||||
|
||||
@@ -24,26 +24,26 @@ class Domain::Fa::User < ReduxApplicationRecord
|
||||
:scan_error, # user has been removed or otherwise, see state_detail
|
||||
]
|
||||
|
||||
# Who this user follows (join table)
|
||||
has_many :follower_joins,
|
||||
class_name: "::Domain::Fa::Follow",
|
||||
foreign_key: :follower_id,
|
||||
inverse_of: :follower,
|
||||
dependent: :destroy
|
||||
|
||||
# Who this user follows (User model)
|
||||
has_many :follows,
|
||||
through: :follower_joins,
|
||||
source: :followed
|
||||
|
||||
# Who follows this user (join table)
|
||||
has_many :followed_joins,
|
||||
class_name: "::Domain::Fa::Follow",
|
||||
foreign_key: :followed_id,
|
||||
inverse_of: :followed,
|
||||
dependent: :destroy
|
||||
|
||||
# Domain::Fa::User
|
||||
# who this user follows
|
||||
has_many :follows,
|
||||
through: :follower_joins,
|
||||
source: :followed
|
||||
|
||||
# Domain::Fa::User
|
||||
# who follows this user
|
||||
# Who follows this user (User model)
|
||||
has_many :followed_by,
|
||||
through: :followed_joins,
|
||||
source: :follower
|
||||
|
||||
@@ -27,13 +27,23 @@
|
||||
<span class="grow">Favorites</span>
|
||||
<span><%= number_with_delimiter(user.num_favorites, delimiter: ",") %></span>
|
||||
</div>
|
||||
<div class='flex'>
|
||||
<span class="grow">Following</span>
|
||||
<span><%= number_with_delimiter(user.follower_joins.count, delimiter: ",") %></span>
|
||||
</div>
|
||||
<div class='flex'>
|
||||
<span class="grow">Followed by</span>
|
||||
<span><%= number_with_delimiter(user.followed_joins.count, delimiter: ",") %></span>
|
||||
</div>
|
||||
</section>
|
||||
<%= render partial: "user_recent_posts_section", locals: { user: user } %>
|
||||
<section class='border-2 border-slate-300 rounded-md mb-2 overflow-clip'>
|
||||
<% if (profile_html = user.profile_html) %>
|
||||
<div class='text-lg border-b-2 border-b-slate-300 text-slate-600 p-1 italic'>Profile Description</div>
|
||||
<div class='p-2 bg-slate-800 text-slate-200'>
|
||||
<%= sanitized_fa_user_profile_html(profile_html) %>
|
||||
<% cache(user, expires_in: 12.hours) do %>
|
||||
<%= sanitized_fa_user_profile_html(profile_html) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div>(No page description)</div>
|
||||
@@ -42,15 +52,17 @@
|
||||
<section class='border-2 border-slate-300 rounded-md'>
|
||||
<div class='text-lg border-b-2 border-b-slate-300 text-slate-600 p-1 italic'>Similar Users</div>
|
||||
<div class='bg-slate-100'>
|
||||
<% similar = similar_users_by_followed(user) %>
|
||||
<% if similar %>
|
||||
<% similar.each do |user| %>
|
||||
<div class='flex flex-row py-1 px-2 border-b-2 last:border-b-0'>
|
||||
<%= render "inline_link", user: user %>
|
||||
</div>
|
||||
<% cache(user.disco, expires_in: 12.hours) do %>
|
||||
<% similar = similar_users_by_followed(user).includes(:avatar) %>
|
||||
<% if similar %>
|
||||
<% similar.each do |user| %>
|
||||
<div class='flex flex-row py-1 px-2 border-b-2 last:border-b-0'>
|
||||
<%= render "inline_link", user: user %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class='p-2'>No similar users</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class='p-2'>No similar users</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -58,7 +58,7 @@ Rails.application.configure do
|
||||
config.log_tags = [:request_id]
|
||||
|
||||
# Use a different cache store in production.
|
||||
# config.cache_store = :mem_cache_store
|
||||
config.cache_store = :memory_store, { size: 64.megabytes }
|
||||
|
||||
# Use a real queuing backend for Active Job (and separate queues per environment).
|
||||
# config.active_job.queue_adapter = :resque
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
if Rails.env.development? || Rails.env.staging?
|
||||
Rack::MiniProfiler.config.position = "top-right"
|
||||
Rack::MiniProfiler.config.disable_caching = false
|
||||
Rack::MiniProfiler.config.skip_paths = [/\/blobs\/.+\/contents.jpg$/]
|
||||
end
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
PgHero.config["explain"] = "analyze"
|
||||
PgHero.config["explain_timeout_sec"] = 60
|
||||
|
||||
Reference in New Issue
Block a user