cache pet images on items#show, in case that's what's being a super-slow jerkface

This commit is contained in:
Emi Matchu 2013-12-05 15:22:43 -06:00
parent cc7ac363dd
commit f07996d762
9 changed files with 88 additions and 61 deletions

View file

@ -2,7 +2,8 @@
var PREVIEW_SWF_ID = 'item-preview-swf', var PREVIEW_SWF_ID = 'item-preview-swf',
PREVIEW_SWF = document.getElementById(PREVIEW_SWF_ID), PREVIEW_SWF = document.getElementById(PREVIEW_SWF_ID),
speciesList = $('#item-preview a'), speciesEls,
petTypeEls,
customize_more_el = $('#customize-more'), customize_more_el = $('#customize-more'),
MainWardrobe; MainWardrobe;
@ -46,7 +47,7 @@ function PetType() {
this.setAsCurrent = function () { this.setAsCurrent = function () {
PetType.current = this; PetType.current = this;
speciesList.filter('.current').removeClass('current'); petTypeEls.filter('.current').removeClass('current');
this.link.addClass('current'); this.link.addClass('current');
customize_more_el.attr('href', customize_more_el.attr('href',
'http://impress.openneo.net/wardrobe?species=' + this.species_id + 'http://impress.openneo.net/wardrobe?species=' + this.species_id +
@ -213,16 +214,40 @@ Preview.embed(PREVIEW_SWF_ID);
Item.createFromLocation().setAsCurrent(); Item.createFromLocation().setAsCurrent();
Item.current.name = $('#item-name').text(); Item.current.name = $('#item-name').text();
PetType.createFromLink(speciesList.eq(Math.floor(Math.random()*speciesList.length))).setAsCurrent(); // Choose only supported species, and remove the unsupported.
var supportedSpeciesIds = $('#item-preview-species').attr('data-supported-species-ids').split(',');
var supportedSpeciesIdPresenceMap = {};
for(var i = 0; i < supportedSpeciesIds.length; i++) {
supportedSpeciesIdPresenceMap[supportedSpeciesIds[i]] = true;
}
speciesEls = $('#item-preview-species > li').filter(function() {
var supported = supportedSpeciesIdPresenceMap[this.getAttribute('data-id')];
if(!supported) this.parentNode.removeChild(this);
return supported;
});
speciesList.each(function () { // Choose random pet type for each species.
speciesEls.each(function() {
var speciesPetTypeEls = $(this).find('.pet-type');
var chosen = speciesPetTypeEls.eq(Math.floor(Math.random()*speciesPetTypeEls.length));
speciesPetTypeEls.not(chosen).remove();
});
petTypeEls = speciesEls.find('.pet-type');
// Choose random starting pet type
PetType.createFromLink(petTypeEls.eq(Math.floor(Math.random()*petTypeEls.length))).setAsCurrent();
// Setup pet type click behavior
petTypeEls.each(function () {
var el = $(this); var el = $(this);
PetType.createFromLink(el); PetType.createFromLink(el);
}).live('click', function (e) { }).click(function (e) {
e.preventDefault();
PetType.all[$(this).data('id')].setAsCurrent(); PetType.all[$(this).data('id')].setAsCurrent();
}); });
// Load the other pet type data in 5 seconds, to save database effort in case
// the user decides to bounce.
setTimeout($.proxy(Item.current, 'loadAllStandard'), 5000); setTimeout($.proxy(Item.current, 'loadAllStandard'), 5000);
window.MainWardrobe = {View: {Outfit: {setFlashIsReady: previewSWFIsReady}}} window.MainWardrobe = {View: {Outfit: {setFlashIsReady: previewSWFIsReady}}}

View file

@ -36,17 +36,18 @@ body.items-show
#item-preview #item-preview
+clearfix +clearfix
div > div, > ul
float: left float: left
#item-preview-species #item-preview-species
display: block
width: 400px width: 400px
a, img .pet-type, img
height: 50px height: 50px
width: 50px width: 50px
a .pet-type
+inline-block +inline-block
&.current &.current
background: $module-bg-color background: $module-bg-color
@ -59,6 +60,9 @@ body.items-show
background: transparent background: transparent
outline-color: $error_border_color outline-color: $error_border_color
ul, li
display: inline
#item-preview-error #item-preview-error
display: none display: none
padding: 20px 10px 0 padding: 20px 10px 0

View file

@ -73,6 +73,11 @@ class ItemsController < ApplicationController
@contributors_with_counts = @item.contributors_with_counts @contributors_with_counts = @item.contributors_with_counts
end end
@supported_species_ids = @item.supported_species_ids
unless localized_fragment_exist?("items/show standard_species_images special_color=#{@item.special_color_id}")
@basic_colored_pet_types_by_species_id = PetType.special_color_or_basic(@item.special_color).includes_child_translations.group_by(&:species)
end
@trading_closet_hangers_by_owned = { @trading_closet_hangers_by_owned = {
true => @item.closet_hangers.owned_trading.newest.includes(:user), true => @item.closet_hangers.owned_trading.newest.includes(:user),
false => @item.closet_hangers.wanted_trading.newest.includes(:user) false => @item.closet_hangers.wanted_trading.newest.includes(:user)

View file

@ -27,31 +27,21 @@ module ItemsHelper
end end
end end
def standard_species_images_key_for(item) def standard_species_images_for(pet_types_by_species_id)
versions_count = 1 # TODO pet_types_by_species_id.to_a.sort_by { |s, pt| s.name }.map { |species, pet_types|
"foo" # TODO pet_type_images = pet_types.map { |pet_type|
end image = pet_type_image(pet_type, :happy, :face)
content_tag(:li, image, 'class' => 'pet-type',
def standard_species_images_for(item) 'data-id' => pet_type.id,
build_on_pet_types(item.supported_species, item.special_color) do |pet_type| 'data-body-id' => pet_type.body_id,
image = pet_type_image(pet_type, :happy, :face) 'data-color-id' => pet_type.color.id,
attributes = { 'data-color-name' => pet_type.color.name,
'data-id' => pet_type.id, 'data-species-id' => pet_type.species.id,
'data-body-id' => pet_type.body_id 'data-species-name' => pet_type.species.name)
} }.join.html_safe
[:color, :species].each do |pet_type_attribute_name| content_tag(:li, content_tag(:ul, pet_type_images),
pet_type_attribute = pet_type.send(pet_type_attribute_name) 'data-id' => species.id)
[:id, :name].each do |subattribute_name| }.join.html_safe
attributes["data-#{pet_type_attribute_name}-#{subattribute_name}"] =
pet_type_attribute.send(subattribute_name)
end
end
link_to(
image,
'#',
attributes
)
end
end end
def closet_list_verb(owned) def closet_list_verb(owned)

View file

@ -154,6 +154,10 @@ class Item < ActiveRecord::Base
@special_color ||= determine_special_color @special_color ||= determine_special_color
end end
def special_color_id
special_color.try(:id)
end
protected protected
def determine_special_color def determine_special_color
I18n.with_locale(I18n.default_locale) do I18n.with_locale(I18n.default_locale) do
@ -187,21 +191,17 @@ class Item < ActiveRecord::Base
write_attribute('species_support_ids', replacement) write_attribute('species_support_ids', replacement)
end end
def supported_species def supported_species_ids
body_ids = swf_assets.select([:body_id]).map(&:body_id) body_ids = swf_assets.select([:body_id]).map(&:body_id)
return Species.all if body_ids.include?(0) return Species.select([:id]).map(&:id) if body_ids.include?(0)
pet_types = PetType.where(:body_id => body_ids).select('DISTINCT species_id') pet_types = PetType.where(:body_id => body_ids).select('DISTINCT species_id')
species_ids = pet_types.map(&:species_id) species_ids = pet_types.map(&:species_id)
# If there are multiple known supported species, it probably supports them # If there are multiple known supported species, it probably supports them
# all. (I've never heard of only a handful of species being supported :P) # all. (I've never heard of only a handful of species being supported :P)
species_ids.size > 1 ? Species.all : Species.find(species_ids) species_ids.size >= 2 ? Species.select([:id]).map(&:id) : species_ids
end
def supported_species_ids
supported_species.map(&:id)
end end
def support_species?(species) def support_species?(species)

View file

@ -22,22 +22,15 @@ class PetType < ActiveRecord::Base
scope :includes_child_translations, scope :includes_child_translations,
lambda { includes({:color => :translations, :species => :translations}) } lambda { includes({:color => :translations, :species => :translations}) }
def self.standard_pet_types_by_species_id def self.special_color_or_basic(special_color)
# If we include Color.basic in the query, rather than getting the ID array color_ids = special_color ? [special_color.id] : Color.basic.select([:id]).map(&:id)
# first, it'll do this as a big fat JOIN unnecessarily. On production, where(color_id: color_ids)
# there are tons of pet types and translations to send down, so tons of
# duplicate data is sent and must be merged together properly, both of
# which take serious time. So, this is a surprisingly significant
# performance boost - though I was surprised and impressed that Rails
# includes relations as subqueries. That's cool.
basic_color_ids = Color.basic.select([:id]).map(&:id)
PetType.where(color_id: basic_color_ids).includes_child_translations.
group_by(&:species_id)
end end
def self.standard_body_ids def self.standard_body_ids
[].tap do |body_ids| [].tap do |body_ids|
standard_pet_types_by_species_id.each do |species_id, pet_types| # TODO: the nil hack is lame :P
special_color_or_basic(nil).group_by(&:species_id).each do |species_id, pet_types|
body_ids.concat(pet_types.map(&:body_id)) body_ids.concat(pet_types.map(&:body_id))
end end
end end
@ -45,7 +38,8 @@ class PetType < ActiveRecord::Base
def self.random_basic_per_species(species_ids) def self.random_basic_per_species(species_ids)
random_pet_types = [] random_pet_types = []
standards = self.standard_pet_types_by_species_id # TODO: omg so lame :P
standards = special_color_or_basic(nil).group_by(&:species_id)
species_ids.each do |species_id| species_ids.each do |species_id|
pet_types = standards[species_id] pet_types = standards[species_id]
random_pet_types << pet_types[rand(pet_types.size)] if pet_types random_pet_types << pet_types[rand(pet_types.size)] if pet_types

View file

@ -0,0 +1,8 @@
class PetTypeObserver < ActiveRecord::Observer
include FragmentExpiration
def after_create(pet_type)
images_key = "items/show standard_species_images special_color=#{pet_type.color_id}"
expire_fragment_in_all_locales(images_key)
end
end

View file

@ -78,9 +78,10 @@
:class => 'button' :class => 'button'
#item-preview #item-preview
#item-preview-species %ul#item-preview-species{'data-supported-species-ids' => @supported_species_ids.join(',')}
-# localized_cache random_standard_species_images_key do -# TODO: filter by compatibility
= standard_species_images_for(@item) - localized_cache "items/show standard_species_images special_color=#{@item.special_color_id}" do
= standard_species_images_for(@basic_colored_pet_types_by_species_id)
#item-preview-error #item-preview-error
#item-preview-swf= t '.preview.requirements_not_met' #item-preview-swf= t '.preview.requirements_not_met'

View file

@ -20,7 +20,7 @@ module OpenneoImpressItems
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running # Activate observers that should always be running
config.active_record.observers = :contribution_observer, :item_observer, :user_sweeper config.active_record.observers = :contribution_observer, :item_observer, :pet_type_observer, :user_sweeper
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.