Compare commits
8 commits
6402e5abc3
...
5264947608
| Author | SHA1 | Date | |
|---|---|---|---|
| 5264947608 | |||
| 90407403ba | |||
| 242b85470d | |||
| 43717e2535 | |||
| bc1f7152bf | |||
| 9eaee4a2d4 | |||
| 52ca41dbff | |||
| c03e7446e3 |
7 changed files with 127 additions and 292 deletions
|
|
@ -74,15 +74,6 @@ class AltStyle < ApplicationRecord
|
||||||
Item.appearances_for(items, self, ...)
|
Item.appearances_for(items, self, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
def biology=(biology)
|
|
||||||
# TODO: This is very similar to what `PetState` does, but like… much much
|
|
||||||
# more compact? Idk if I'm missing something, or if I was just that much
|
|
||||||
# more clueless back when I wrote it, lol 😅
|
|
||||||
self.swf_assets = biology.values.map do |asset_data|
|
|
||||||
SwfAsset.from_biology_data(self.body_id, asset_data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# At time of writing, most batches of Alt Styles thumbnails used a simple
|
# At time of writing, most batches of Alt Styles thumbnails used a simple
|
||||||
# pattern for the item thumbnail URL, but that's not always the case anymore.
|
# pattern for the item thumbnail URL, but that's not always the case anymore.
|
||||||
# For now, let's keep using this format as the default value when creating a
|
# For now, let's keep using this format as the default value when creating a
|
||||||
|
|
|
||||||
|
|
@ -405,40 +405,13 @@ class Item < ApplicationRecord
|
||||||
PetType.where(body_id: compatible_body_ids)
|
PetType.where(body_id: compatible_body_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_assets!
|
|
||||||
if @parent_swf_asset_relationships_to_update && @current_body_id
|
|
||||||
new_swf_asset_ids = @parent_swf_asset_relationships_to_update.map(&:swf_asset_id)
|
|
||||||
rels = ParentSwfAssetRelationship.arel_table
|
|
||||||
swf_assets = SwfAsset.arel_table
|
|
||||||
|
|
||||||
# If a relationship used to bind an item and asset for this body type,
|
|
||||||
# but doesn't in this sample, the two have been unbound. Delete the
|
|
||||||
# relationship.
|
|
||||||
ids_to_delete = self.parent_swf_asset_relationships.
|
|
||||||
select(rels[:id]).
|
|
||||||
joins(:swf_asset).
|
|
||||||
where(rels[:swf_asset_id].not_in(new_swf_asset_ids)).
|
|
||||||
where(swf_assets[:body_id].in([@current_body_id, 0])).
|
|
||||||
map(&:id)
|
|
||||||
|
|
||||||
unless ids_to_delete.empty?
|
|
||||||
ParentSwfAssetRelationship.where(:id => ids_to_delete).delete_all
|
|
||||||
end
|
|
||||||
|
|
||||||
@parent_swf_asset_relationships_to_update.each do |rel|
|
|
||||||
rel.save!
|
|
||||||
rel.swf_asset.save!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def body_specific?
|
def body_specific?
|
||||||
# If there are species support IDs (it's not empty), the item is
|
# If there are species support IDs (it's not empty), the item is
|
||||||
# body-specific. If it's empty, it fits everyone the same.
|
# body-specific. If it's empty, it fits everyone the same.
|
||||||
explicitly_body_specific? || !species_support_ids.empty?
|
explicitly_body_specific? || !species_support_ids.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_origin_registry_info(info, locale)
|
def add_origin_registry_info(info)
|
||||||
# bear in mind that numbers from registries are floats
|
# bear in mind that numbers from registries are floats
|
||||||
species_support_strs = info['species_support'] || []
|
species_support_strs = info['species_support'] || []
|
||||||
self.species_support_ids = species_support_strs.map(&:to_i)
|
self.species_support_ids = species_support_strs.map(&:to_i)
|
||||||
|
|
@ -457,16 +430,6 @@ class Item < ApplicationRecord
|
||||||
self.zones_restrict = info['zones_restrict']
|
self.zones_restrict = info['zones_restrict']
|
||||||
end
|
end
|
||||||
|
|
||||||
def pending_swf_assets
|
|
||||||
@parent_swf_asset_relationships_to_update.inject([]) do |all_swf_assets, relationship|
|
|
||||||
all_swf_assets << relationship.swf_asset
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parent_swf_asset_relationships_to_update=(rels)
|
|
||||||
@parent_swf_asset_relationships_to_update = rels
|
|
||||||
end
|
|
||||||
|
|
||||||
# NOTE: Adding the JSON serializer makes `as_json` treat this like a model
|
# NOTE: Adding the JSON serializer makes `as_json` treat this like a model
|
||||||
# instead of like a hash, so you can target its children with things like
|
# instead of like a hash, so you can target its children with things like
|
||||||
# the `include` option. This feels clunky though, I wish I had something a
|
# the `include` option. This feels clunky though, I wish I had something a
|
||||||
|
|
@ -638,90 +601,4 @@ class Item < ApplicationRecord
|
||||||
|
|
||||||
items
|
items
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.collection_from_pet_type_and_registries(pet_type, info_registry, asset_registry, scope=Item.all)
|
|
||||||
# bear in mind that registries are arrays with many nil elements,
|
|
||||||
# due to how the parser works
|
|
||||||
|
|
||||||
# Collect existing items
|
|
||||||
items = {}
|
|
||||||
item_ids = []
|
|
||||||
info_registry.each do |item_id, info|
|
|
||||||
if info && info[:is_compatible]
|
|
||||||
item_ids << item_id.to_i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Collect existing relationships
|
|
||||||
existing_relationships_by_item_id_and_swf_asset_id = {}
|
|
||||||
existing_items = scope.where(id: item_ids).
|
|
||||||
includes(:parent_swf_asset_relationships)
|
|
||||||
existing_items.each do |item|
|
|
||||||
items[item.id] = item
|
|
||||||
relationships_by_swf_asset_id = {}
|
|
||||||
item.parent_swf_asset_relationships.each do |relationship|
|
|
||||||
relationships_by_swf_asset_id[relationship.swf_asset_id] = relationship
|
|
||||||
end
|
|
||||||
existing_relationships_by_item_id_and_swf_asset_id[item.id] =
|
|
||||||
relationships_by_swf_asset_id
|
|
||||||
end
|
|
||||||
|
|
||||||
# Collect existing assets
|
|
||||||
swf_asset_ids = []
|
|
||||||
asset_registry.each do |asset_id, asset_data|
|
|
||||||
swf_asset_ids << asset_id.to_i if asset_data
|
|
||||||
end
|
|
||||||
existing_swf_assets = SwfAsset.object_assets.includes(:zone).
|
|
||||||
where(remote_id: swf_asset_ids)
|
|
||||||
existing_swf_assets_by_remote_id = {}
|
|
||||||
existing_swf_assets.each do |swf_asset|
|
|
||||||
existing_swf_assets_by_remote_id[swf_asset.remote_id] = swf_asset
|
|
||||||
end
|
|
||||||
|
|
||||||
# With each asset in the registry,
|
|
||||||
relationships_by_item_id = {}
|
|
||||||
asset_registry.each do |asset_id, asset_data|
|
|
||||||
if asset_data
|
|
||||||
# Build and update the item
|
|
||||||
item_id = asset_data[:obj_info_id].to_i
|
|
||||||
next unless item_ids.include?(item_id) # skip incompatible (Uni Bug)
|
|
||||||
item = items[item_id]
|
|
||||||
unless item
|
|
||||||
item = Item.new
|
|
||||||
item.id = item_id
|
|
||||||
items[item_id] = item
|
|
||||||
end
|
|
||||||
item.add_origin_registry_info info_registry[item.id.to_s], I18n.default_locale
|
|
||||||
item.current_body_id = pet_type.body_id
|
|
||||||
|
|
||||||
# Build and update the SWF
|
|
||||||
swf_asset_remote_id = asset_data[:asset_id].to_i
|
|
||||||
swf_asset = existing_swf_assets_by_remote_id[swf_asset_remote_id]
|
|
||||||
unless swf_asset
|
|
||||||
swf_asset = SwfAsset.new
|
|
||||||
swf_asset.remote_id = swf_asset_remote_id
|
|
||||||
end
|
|
||||||
swf_asset.origin_object_data = asset_data
|
|
||||||
swf_asset.origin_pet_type = pet_type
|
|
||||||
swf_asset.item = item
|
|
||||||
|
|
||||||
# Build and update the relationship
|
|
||||||
relationship = existing_relationships_by_item_id_and_swf_asset_id[item.id][swf_asset.id] rescue nil
|
|
||||||
unless relationship
|
|
||||||
relationship = ParentSwfAssetRelationship.new
|
|
||||||
relationship.parent = item
|
|
||||||
end
|
|
||||||
relationship.swf_asset = swf_asset
|
|
||||||
relationships_by_item_id[item_id] ||= []
|
|
||||||
relationships_by_item_id[item_id] << relationship
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Set up the relationships to be updated on item save
|
|
||||||
relationships_by_item_id.each do |item_id, relationships|
|
|
||||||
items[item_id].parent_swf_asset_relationships_to_update = relationships
|
|
||||||
end
|
|
||||||
|
|
||||||
items.values
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@ class Pet < ApplicationRecord
|
||||||
|
|
||||||
def load!(timeout: nil)
|
def load!(timeout: nil)
|
||||||
viewer_data_hash = Neopets::CustomPets.fetch_viewer_data(name, timeout:)
|
viewer_data_hash = Neopets::CustomPets.fetch_viewer_data(name, timeout:)
|
||||||
use_viewer_data(ViewerData.new(viewer_data_hash))
|
use_modeling_snapshot(ModelingSnapshot.new(viewer_data_hash))
|
||||||
end
|
end
|
||||||
|
|
||||||
def use_viewer_data(viewer_data)
|
def use_modeling_snapshot(snapshot)
|
||||||
self.pet_type = viewer_data.pet_type
|
self.pet_type = snapshot.pet_type
|
||||||
@pet_state = viewer_data.pet_state
|
@pet_state = snapshot.pet_state
|
||||||
@alt_style = viewer_data.alt_style
|
@alt_style = snapshot.alt_style
|
||||||
@items = viewer_data.items
|
@items = snapshot.items
|
||||||
end
|
end
|
||||||
|
|
||||||
def wardrobe_query
|
def wardrobe_query
|
||||||
|
|
@ -39,17 +39,8 @@ class Pet < ApplicationRecord
|
||||||
before_validation do
|
before_validation do
|
||||||
pet_type.save!
|
pet_type.save!
|
||||||
@pet_state.save! if @pet_state
|
@pet_state.save! if @pet_state
|
||||||
|
@alt_style.save! if @alt_style
|
||||||
if @items
|
(@items || []).each(&:save!)
|
||||||
@items.each do |item|
|
|
||||||
item.save! if item.changed?
|
|
||||||
item.handle_assets!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if @alt_style
|
|
||||||
@alt_style.save!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.load(name, **options)
|
def self.load(name, **options)
|
||||||
|
|
@ -59,91 +50,5 @@ class Pet < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class UnexpectedDataFormat < RuntimeError;end
|
class UnexpectedDataFormat < RuntimeError;end
|
||||||
|
|
||||||
# A representation of a Neopets::CustomPets viewer data response, translated
|
|
||||||
# to DTI's database models!
|
|
||||||
class ViewerData
|
|
||||||
def initialize(viewer_data_hash)
|
|
||||||
@custom_pet = viewer_data_hash[:custom_pet]
|
|
||||||
@object_info_registry = viewer_data_hash[:object_info_registry]
|
|
||||||
@object_asset_registry = viewer_data_hash[:object_asset_registry]
|
|
||||||
end
|
|
||||||
|
|
||||||
def pet_type
|
|
||||||
@pet_type ||= begin
|
|
||||||
raise UnexpectedDataFormat unless @custom_pet[:species_id]
|
|
||||||
raise UnexpectedDataFormat unless @custom_pet[:color_id]
|
|
||||||
raise UnexpectedDataFormat unless @custom_pet[:body_id]
|
|
||||||
|
|
||||||
@custom_pet => {species_id:, color_id:}
|
|
||||||
PetType.find_or_initialize_by(species_id:, color_id:).tap do |pet_type|
|
|
||||||
# Apply the pet's body ID to the pet type, unless it's wearing an alt
|
|
||||||
# style, in which case ignore it, because it's the *alt style*'s body ID.
|
|
||||||
# (This can theoretically cause a problem saving a new pet type when
|
|
||||||
# there's an alt style too!)
|
|
||||||
pet_type.body_id = @custom_pet[:body_id] unless @custom_pet[:alt_style]
|
|
||||||
if pet_type.body_id.nil?
|
|
||||||
raise UnexpectedDataFormat,
|
|
||||||
"can't process alt style on first occurrence of pet type"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Try using this pet for the pet type's thumbnail, but don't worry
|
|
||||||
# if it fails.
|
|
||||||
begin
|
|
||||||
pet_type.consider_pet_image(@custom_pet[:name])
|
|
||||||
rescue => error
|
|
||||||
Rails.logger.warn "Failed to load pet image: #{error.full_message}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pet_state
|
|
||||||
@pet_state ||= begin
|
|
||||||
# Choose the right biology, depending on if there's an alt style.
|
|
||||||
pet_state_biology = @custom_pet[:alt_style].present? ?
|
|
||||||
@custom_pet[:original_biology] :
|
|
||||||
@custom_pet[:biology_by_zone]
|
|
||||||
raise UnexpectedDataFormat if pet_state_biology.empty?
|
|
||||||
|
|
||||||
# Then, set up the biology assets.
|
|
||||||
body_id = @custom_pet[:body_id].to_i
|
|
||||||
swf_assets = pet_state_biology.values.map do |biology_data|
|
|
||||||
SwfAsset.from_biology_data(body_id, biology_data)
|
|
||||||
end
|
|
||||||
swf_asset_ids = swf_assets.map(&:remote_id).sort.join(",")
|
|
||||||
|
|
||||||
# Then, set up the pet state, using these biology assets.
|
|
||||||
pet_type.pet_states.find_or_initialize_by(swf_asset_ids:).tap do |pet_state|
|
|
||||||
pet_state.swf_assets = swf_assets
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def alt_style
|
|
||||||
@alt_style ||= begin
|
|
||||||
return nil unless @custom_pet[:alt_style]
|
|
||||||
|
|
||||||
raise UnexpectedDataFormat unless @custom_pet[:alt_color]
|
|
||||||
raise UnexpectedDataFormat if @custom_pet[:biology_by_zone].empty?
|
|
||||||
|
|
||||||
id = @custom_pet[:alt_style].to_i
|
|
||||||
AltStyle.find_or_initialize_by(id:).tap do |alt_style|
|
|
||||||
alt_style.assign_attributes(
|
|
||||||
color_id: @custom_pet[:alt_color].to_i,
|
|
||||||
species_id: @custom_pet[:species_id].to_i,
|
|
||||||
body_id: @custom_pet[:body_id].to_i,
|
|
||||||
biology: @custom_pet[:biology_by_zone],
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def items
|
|
||||||
@items ||= Item.collection_from_pet_type_and_registries(
|
|
||||||
pet_type, @object_info_registry, @object_asset_registry
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
107
app/models/pet/modeling_snapshot.rb
Normal file
107
app/models/pet/modeling_snapshot.rb
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
# A representation of a Neopets::CustomPets viewer data response, translated
|
||||||
|
# to DTI's database models!
|
||||||
|
class Pet::ModelingSnapshot
|
||||||
|
def initialize(viewer_data_hash)
|
||||||
|
@custom_pet = viewer_data_hash[:custom_pet]
|
||||||
|
@object_info_registry = viewer_data_hash[:object_info_registry]
|
||||||
|
@object_asset_registry = viewer_data_hash[:object_asset_registry]
|
||||||
|
end
|
||||||
|
|
||||||
|
def pet_type
|
||||||
|
@pet_type ||= begin
|
||||||
|
raise Pet::UnexpectedDataFormat unless @custom_pet[:species_id]
|
||||||
|
raise Pet::UnexpectedDataFormat unless @custom_pet[:color_id]
|
||||||
|
raise Pet::UnexpectedDataFormat unless @custom_pet[:body_id]
|
||||||
|
|
||||||
|
@custom_pet => {species_id:, color_id:}
|
||||||
|
PetType.find_or_initialize_by(species_id:, color_id:).tap do |pet_type|
|
||||||
|
# Apply the pet's body ID to the pet type, unless it's wearing an alt
|
||||||
|
# style, in which case ignore it, because it's the *alt style*'s body ID.
|
||||||
|
# (This can theoretically cause a problem saving a new pet type when
|
||||||
|
# there's an alt style too!)
|
||||||
|
pet_type.body_id = @custom_pet[:body_id] unless @custom_pet[:alt_style]
|
||||||
|
if pet_type.body_id.nil?
|
||||||
|
raise Pet::UnexpectedDataFormat,
|
||||||
|
"can't process alt style on first occurrence of pet type"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Try using this pet for the pet type's thumbnail, but don't worry
|
||||||
|
# if it fails.
|
||||||
|
begin
|
||||||
|
pet_type.consider_pet_image(@custom_pet[:name])
|
||||||
|
rescue => error
|
||||||
|
Rails.logger.warn "Failed to load pet image: #{error.full_message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pet_state
|
||||||
|
@pet_state ||= begin
|
||||||
|
swf_asset_ids = biology_assets.map(&:remote_id)
|
||||||
|
pet_type.pet_states.find_or_initialize_by(swf_asset_ids:).tap do |pet_state|
|
||||||
|
pet_state.swf_assets = biology_assets
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def alt_style
|
||||||
|
@alt_style ||= begin
|
||||||
|
return nil unless @custom_pet[:alt_style]
|
||||||
|
raise Pet::UnexpectedDataFormat unless @custom_pet[:alt_color]
|
||||||
|
|
||||||
|
id = @custom_pet[:alt_style].to_i
|
||||||
|
AltStyle.find_or_initialize_by(id:).tap do |alt_style|
|
||||||
|
alt_style.assign_attributes(
|
||||||
|
color_id: @custom_pet[:alt_color].to_i,
|
||||||
|
species_id: @custom_pet[:species_id].to_i,
|
||||||
|
body_id: @custom_pet[:body_id].to_i,
|
||||||
|
swf_assets: alt_style_assets,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def items
|
||||||
|
@items ||= @object_info_registry.map do |id, item_data|
|
||||||
|
Item.find_or_initialize_by(id:).tap do |item|
|
||||||
|
item.add_origin_registry_info item_data
|
||||||
|
item.swf_assets = item_assets_for id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def biology_assets
|
||||||
|
@biology_assets ||= begin
|
||||||
|
biology = @custom_pet[:alt_style].present? ?
|
||||||
|
@custom_pet[:original_biology] :
|
||||||
|
@custom_pet[:biology_by_zone]
|
||||||
|
assets_from_biology(biology)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def item_assets_for(item_id)
|
||||||
|
all_infos = @object_asset_registry.values
|
||||||
|
infos = all_infos.select { |a| a[:obj_info_id].to_i == item_id.to_i }
|
||||||
|
infos.map do |asset_data|
|
||||||
|
remote_id = asset_data[:asset_id].to_i
|
||||||
|
SwfAsset.find_or_initialize_by(type: "object", remote_id:).tap do |swf_asset|
|
||||||
|
swf_asset.origin_pet_type = pet_type
|
||||||
|
swf_asset.origin_object_data = asset_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def alt_style_assets
|
||||||
|
raise Pet::UnexpectedDataFormat if @custom_pet[:biology_by_zone].empty?
|
||||||
|
@alt_style_assets ||= assets_from_biology(@custom_pet[:biology_by_zone])
|
||||||
|
end
|
||||||
|
|
||||||
|
def assets_from_biology(biology)
|
||||||
|
raise Pet::UnexpectedDataFormat if biology.empty?
|
||||||
|
body_id = @custom_pet[:body_id].to_i
|
||||||
|
biology.values.map { |b| SwfAsset.from_biology_data(body_id, b) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -9,6 +9,8 @@ class PetState < ApplicationRecord
|
||||||
has_many :parent_swf_asset_relationships, :as => :parent
|
has_many :parent_swf_asset_relationships, :as => :parent
|
||||||
has_many :swf_assets, :through => :parent_swf_asset_relationships
|
has_many :swf_assets, :through => :parent_swf_asset_relationships
|
||||||
|
|
||||||
|
serialize :swf_asset_ids, coder: Serializers::IntegerSet, type: Array
|
||||||
|
|
||||||
belongs_to :pet_type
|
belongs_to :pet_type
|
||||||
|
|
||||||
delegate :species_id, :species, :color_id, :color, to: :pet_type
|
delegate :species_id, :species, :color_id, :color, to: :pet_type
|
||||||
|
|
@ -92,50 +94,18 @@ class PetState < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def reassign_children_to!(main_pet_state)
|
|
||||||
self.contributions.each do |contribution|
|
|
||||||
contribution.contributed = main_pet_state
|
|
||||||
contribution.save
|
|
||||||
end
|
|
||||||
self.outfits.each do |outfit|
|
|
||||||
outfit.pet_state = main_pet_state
|
|
||||||
outfit.save
|
|
||||||
end
|
|
||||||
ParentSwfAssetRelationship.where(ParentSwfAssetRelationship.arel_table[:parent_id].eq(self.id)).delete_all
|
|
||||||
end
|
|
||||||
|
|
||||||
def reassign_duplicates!
|
|
||||||
raise "This may only be applied to pet states that represent many duplicate entries" unless duplicate_ids
|
|
||||||
pet_states = duplicate_ids.split(',').map do |id|
|
|
||||||
PetState.find(id.to_i)
|
|
||||||
end
|
|
||||||
main_pet_state = pet_states.shift
|
|
||||||
pet_states.each do |pet_state|
|
|
||||||
pet_state.reassign_children_to!(main_pet_state)
|
|
||||||
pet_state.destroy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def sort_swf_asset_ids!
|
|
||||||
self.swf_asset_ids = swf_asset_ids_array.sort.join(',')
|
|
||||||
end
|
|
||||||
|
|
||||||
def swf_asset_ids
|
|
||||||
self['swf_asset_ids']
|
|
||||||
end
|
|
||||||
|
|
||||||
def swf_asset_ids_array
|
|
||||||
swf_asset_ids.split(',').map(&:to_i)
|
|
||||||
end
|
|
||||||
|
|
||||||
def swf_asset_ids=(ids)
|
|
||||||
self['swf_asset_ids'] = ids
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_param
|
def to_param
|
||||||
"#{id}-#{pose.split('_').map(&:capitalize).join('-')}"
|
"#{id}-#{pose.split('_').map(&:capitalize).join('-')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Because our column is named `swf_asset_ids`, we need to ensure writes to
|
||||||
|
# it go to the attribute, and not the thing ActiveRecord does of finding the
|
||||||
|
# relevant `swf_assets`.
|
||||||
|
# TODO: Consider renaming the column to `cached_swf_asset_ids`?
|
||||||
|
def swf_asset_ids=(new_swf_asset_ids)
|
||||||
|
write_attribute(:swf_asset_ids, new_swf_asset_ids)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# A helper for the `pose=` method.
|
# A helper for the `pose=` method.
|
||||||
|
|
|
||||||
|
|
@ -320,14 +320,6 @@ class SwfAsset < ApplicationRecord
|
||||||
swf_asset
|
swf_asset
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.from_wardrobe_link_params(ids)
|
|
||||||
where((
|
|
||||||
arel_table[:remote_id].in(ids[:biology]).and(arel_table[:type].eq('biology'))
|
|
||||||
).or(
|
|
||||||
arel_table[:remote_id].in(ids[:object]).and(arel_table[:type].eq('object'))
|
|
||||||
))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Given a list of SWF assets, ensure all of their manifests are loaded, with
|
# Given a list of SWF assets, ensure all of their manifests are loaded, with
|
||||||
# fast concurrent execution!
|
# fast concurrent execution!
|
||||||
def self.preload_manifests(swf_assets)
|
def self.preload_manifests(swf_assets)
|
||||||
|
|
|
||||||
|
|
@ -271,18 +271,11 @@ RSpec.describe Pet, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "its item assets" do
|
context "its item assets" do
|
||||||
# TODO: I wish item assets were set up before saving.
|
|
||||||
# Once we change this, we can un-mark some tests as pending.
|
|
||||||
before { pet.save! }
|
|
||||||
|
|
||||||
let(:assets_by_item) { pet.items.to_h { |item| [item.id, item.swf_assets.to_a] } }
|
let(:assets_by_item) { pet.items.to_h { |item| [item.id, item.swf_assets.to_a] } }
|
||||||
subject(:item_assets) { assets_by_item.values.flatten(1) }
|
subject(:item_assets) { assets_by_item.values.flatten(1) }
|
||||||
let(:asset_ids) { item_assets.map(&:remote_id) }
|
let(:asset_ids) { item_assets.map(&:remote_id) }
|
||||||
|
|
||||||
they("are all new") do
|
they("are all new") { should all be_new_record }
|
||||||
pending("Currently, pets must be saved before assets are assigned.")
|
|
||||||
should all be_new_record
|
|
||||||
end
|
|
||||||
they("match the expected IDs") do
|
they("match the expected IDs") do
|
||||||
expect(asset_ids).to contain_exactly(16933, 108567, 410722)
|
expect(asset_ids).to contain_exactly(16933, 108567, 410722)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue