Compare commits

..

6 commits

Author SHA1 Message Date
860b8eef72 Remove not-very-useful caching for homepage modeling
Huh, I hadn't realized that like, we'd already set up the controller to
always *run* basically all of the modeling logic, and the caching in
the view layer wasn't saving us any queries anymore. Kinda silly!

Remove the caching call, just to simplify the codebase (I like to avoid
caching things that don't specifically need it!).

And hey, love that the modeling code in the controller is now *way*
faster to run! You love to see it!
2024-10-02 18:26:49 -07:00
61e22e3943 Oops, remove no-longer-true comment about a code block I just deleted! 2024-10-02 18:20:22 -07:00
03e4233f67 Use cached compatible body IDs on homepage modeling code
This should make it load way faster! Maybe don't even need to mess with
caching the resulting HTML anymore, like we currently do?
2024-10-02 17:55:20 -07:00
b6bddb14be Oops, fix new bug in homepage modeling code
Missed a spot on `Item#basic_body_ids`!
2024-10-02 17:54:14 -07:00
e52838ba70 Use Rails serialize method to save/load cached fields in Item
Just packing some serialization complexity away into its own thing, so
the model code doesn't need to sweat it!
2024-10-02 17:50:42 -07:00
7ba68c52d4 Simplify homepage modeling code a bit
I have some other changes planned too, but these are some easy ones. I
also turn back on this stuff in development, in hopes that my changes
can make these queries fast enough to not be a big deal anymore!
2024-10-02 17:26:32 -07:00
7 changed files with 73 additions and 71 deletions

View file

@ -50,10 +50,9 @@ class OutfitsController < ApplicationController
@colors = Color.alphabetical
@species = Species.alphabetical
# HACK: Skip this in development, because it's slow!
unless Rails.env.development?
newest_items = Item.newest.
select(:id, :name, :updated_at, :thumbnail_url, :rarity_index, :is_manually_nc)
select(:id, :name, :updated_at, :thumbnail_url, :rarity_index,
:is_manually_nc, :cached_compatible_body_ids)
.limit(18)
@newest_modeled_items, @newest_unmodeled_items =
newest_items.partition(&:predicted_fully_modeled?)
@ -70,7 +69,6 @@ class OutfitsController < ApplicationController
@newest_unmodeled_items_predicted_missing_species_by_color[item] = h
@newest_unmodeled_items_predicted_modeled_ratio[item] = item.predicted_modeled_ratio
end
end
@species_count = Species.count

View file

@ -10,6 +10,9 @@ class Item < ApplicationRecord
SwfAssetType = 'object'
serialize :cached_compatible_body_ids, coder: Serializers::IntegerSet
serialize :cached_occupied_zone_ids, coder: Serializers::IntegerSet
has_many :closet_hangers
has_one :contribution, as: :contributed, inverse_of: :contributed
has_one :nc_mall_record
@ -258,8 +261,8 @@ class Item < ApplicationRecord
end
def update_cached_fields
self.cached_occupied_zone_ids = occupied_zone_ids.sort.join(",")
self.cached_compatible_body_ids = compatible_body_ids.sort.join(",")
self.cached_occupied_zone_ids = occupied_zone_ids
self.cached_compatible_body_ids = compatible_body_ids(use_cached: false)
self.save!
end
@ -273,58 +276,35 @@ class Item < ApplicationRecord
write_attribute('species_support_ids', replacement)
end
def support_species?(species)
species_support_ids.blank? || species_support_ids.include?(species.id)
end
def modeled_body_ids
@modeled_body_ids ||= swf_assets.select('DISTINCT body_id').map(&:body_id)
end
def modeled_color_ids
# Might be empty if modeled_body_ids is 0. But it's currently not called
# in that scenario, so, whatever.
@modeled_color_ids ||= PetType.select('DISTINCT color_id').
where(body_id: modeled_body_ids).
map(&:color_id)
end
def basic_body_ids
@basic_body_ids ||= begin
basic_color_ids ||= Color.select([:id]).basic.map(&:id)
PetType.select('DISTINCT body_id').
where(color_id: basic_color_ids).map(&:body_id)
end
end
def predicted_body_ids
@predicted_body_ids ||= if modeled_body_ids.include?(0)
@predicted_body_ids ||= if compatible_body_ids.include?(0)
# Oh, look, it's already known to fit everybody! Sweet. We're done. (This
# isn't folded into the case below, in case this item somehow got a
# body-specific and non-body-specific asset. In all the cases I've seen
# it, that indicates a glitched item, but this method chooses to reflect
# behavior elsewhere in the app by saying that we can put this item on
# anybody. (Heh. Any body.))
modeled_body_ids
elsif modeled_body_ids.size == 1
compatible_body_ids
elsif compatible_body_ids.size == 1
# This might just be a species-specific item. Let's be conservative in
# our prediction, though we'll revise it if we see another body ID.
modeled_body_ids
compatible_body_ids
else
# If an item is worn by more than one body, then it must be wearable by
# all bodies of the same color. (To my knowledge, anyway. I'm not aware
# of any exceptions.) So, let's find those bodies by first finding those
# colors.
basic_modeled_body_ids, nonbasic_modeled_body_ids = modeled_body_ids.
partition { |bi| basic_body_ids.include?(bi) }
basic_body_ids = PetType.basic_body_ids
basic_compatible_body_ids, nonbasic_compatible_body_ids =
compatible_body_ids.partition { |bi| basic_body_ids.include?(bi) }
output = []
if basic_modeled_body_ids.present?
if basic_compatible_body_ids.present?
output += basic_body_ids
end
if nonbasic_modeled_body_ids.present?
if nonbasic_compatible_body_ids.present?
nonbasic_modeled_color_ids = PetType.select('DISTINCT color_id').
where(body_id: nonbasic_modeled_body_ids).
where(body_id: nonbasic_compatible_body_ids).
map(&:color_id)
output += PetType.select('DISTINCT body_id').
where(color_id: nonbasic_modeled_color_ids).
@ -335,7 +315,7 @@ class Item < ApplicationRecord
end
def predicted_missing_body_ids
@predicted_missing_body_ids ||= predicted_body_ids - modeled_body_ids
@predicted_missing_body_ids ||= predicted_body_ids - compatible_body_ids
end
def predicted_missing_standard_body_ids_by_species_id
@ -355,9 +335,8 @@ class Item < ApplicationRecord
end
def predicted_missing_nonstandard_body_pet_types
PetType.joins(:color).
where(body_id: predicted_missing_body_ids - basic_body_ids,
colors: {standard: false})
body_ids = predicted_missing_body_ids - PetType.basic_body_ids
PetType.joins(:color).where(body_id: body_ids, colors: {standard: false})
end
def predicted_missing_nonstandard_body_ids_by_species_by_color
@ -387,7 +366,7 @@ class Item < ApplicationRecord
end
def predicted_modeled_ratio
modeled_body_ids.size.to_f / predicted_body_ids.size
compatible_body_ids.size.to_f / predicted_body_ids.size
end
def as_json(options={})
@ -397,7 +376,9 @@ class Item < ApplicationRecord
}.merge(options))
end
def compatible_body_ids
def compatible_body_ids(use_cached: true)
return cached_compatible_body_ids if use_cached
swf_assets.map(&:body_id).uniq
end

View file

@ -116,6 +116,10 @@ class PetType < ApplicationRecord
"#{color.human_name}-#{species.human_name}"
end
def self.basic_body_ids
PetType.basic.distinct.pluck(:body_id)
end
def self.all_by_ids_or_children(ids, pet_states)
pet_states_by_pet_type_id = {}
pet_states.each do |pet_state|

View file

@ -90,7 +90,6 @@
%h3= t '.newest_items.unmodeled.header'
%ul#newest-unmodeled-items
- @newest_unmodeled_items.each do |item|
- cache "items/#{item.id} modeling_progress locale=#{I18n.locale} updated_at=#{item.updated_at.to_i}" do
%li{'data-item-id' => item.id}
= link_to image_tag(item.thumbnail_url), item, :class => 'image-link'
= link_to item, :class => 'header' do

View file

@ -0,0 +1,9 @@
class AllowNullInItemsCachedFields < ActiveRecord::Migration[7.2]
def change
# This is a bit more compatible with ActiveRecord's `serialize` utility,
# which seems pretty insistent that empty arrays should be saved as `NULL`,
# rather than the empty string our serializer would return if called :(
change_column_null :items, :cached_compatible_body_ids, true
change_column_null :items, :cached_occupied_zone_ids, true
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.2].define(version: 2024_10_01_052510) do
ActiveRecord::Schema[7.2].define(version: 2024_10_03_004726) do
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
t.integer "species_id", null: false
t.integer "color_id", null: false
@ -137,8 +137,8 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_01_052510) do
t.text "description", size: :medium, null: false
t.string "rarity", default: "", null: false
t.integer "dyeworks_base_item_id"
t.string "cached_occupied_zone_ids", default: "", null: false
t.text "cached_compatible_body_ids", default: "", null: false
t.string "cached_occupied_zone_ids", default: ""
t.text "cached_compatible_body_ids", default: ""
t.index ["dyeworks_base_item_id"], name: "index_items_on_dyeworks_base_item_id"
t.index ["modeling_status_hint", "created_at", "id"], name: "items_modeling_status_hint_and_created_at_and_id"
t.index ["modeling_status_hint", "created_at"], name: "items_modeling_status_hint_and_created_at"

View file

@ -0,0 +1,11 @@
module Serializers
module IntegerSet
def self.dump(array)
array.sort.join(",")
end
def self.load(string)
(string || "").split(",").map(&:to_i)
end
end
end