Compare commits

..

No commits in common. "3ac9e7ce6994352171bdbd26f2a0e7fb91c0dedd" and "0705f66f6db85916aa4bea45f1000cca1dbff473" have entirely different histories.

12 changed files with 79 additions and 95 deletions

View file

@ -235,6 +235,7 @@ class ClosetHangersController < ApplicationController
lists,
hangers_scope: hangers_scope,
items_scope: items_scope,
item_translations_scope: item_translations_scope,
)
lists.group_by(&:hangers_owned)
end
@ -247,6 +248,7 @@ class ClosetHangersController < ApplicationController
ClosetHanger.preload_items(
hangers,
items_scope: items_scope,
item_translations_scope: item_translations_scope,
)
hangers.group_by(&:owned)
else
@ -259,8 +261,12 @@ class ClosetHangersController < ApplicationController
end
def items_scope
Item.select(:id, :name, :description, :thumbnail_url, :rarity_index,
:is_manually_nc)
Item.select(:id, :thumbnail_url, :rarity_index, :is_manually_nc)
end
def item_translations_scope
Item::Translation.select(:id, :item_id, :locale, :name, :description).
where(locale: I18n.locale)
end
def owned

View file

@ -10,6 +10,7 @@ class ContributionsController < ApplicationController
Contribution.preload_contributeds_and_parents(
@contributions,
:scopes => {
'Item' => Item.includes(:translations),
'PetType' => PetType.includes(:species, :color),
'AltStyle' => AltStyle.includes(:species, :color),
}

View file

@ -11,8 +11,10 @@ class ItemsController < ApplicationController
else
per_page = 30
end
@items = @query.results.paginate(
page: params[:page], per_page: per_page)
# Note that we sort by name by hand, since we might have to use
# fallbacks after the fact
@items = @query.results.includes(:translations).
paginate(page: params[:page], per_page: per_page)
assign_closeted!
respond_to do |format|
format.html {
@ -44,7 +46,7 @@ class ItemsController < ApplicationController
respond_to do |format|
format.html {
@campaign = Fundraising::Campaign.current rescue nil
@newest_items = Item.newest.limit(18)
@newest_items = Item.newest.includes(:translations).limit(18)
}
format.js { render json: {error: '$q required'}}
end
@ -86,7 +88,8 @@ class ItemsController < ApplicationController
raise ActiveRecord::RecordNotFound, 'Pet type not found'
end
@items = @pet_type.needed_items.order(:name)
@items = @pet_type.needed_items.includes(:translations).
alphabetize_by_translations
assign_closeted!
respond_to do |format|

View file

@ -51,8 +51,8 @@ class OutfitsController < ApplicationController
@species = Species.alphabetical
newest_items = Item.newest.
select(:id, :name, :updated_at, :thumbnail_url, :rarity_index, :is_manually_nc)
.limit(18)
select(:id, :updated_at, :thumbnail_url, :rarity_index, :is_manually_nc).
includes(:translations).limit(18)
@newest_modeled_items, @newest_unmodeled_items =
newest_items.partition(&:predicted_fully_modeled?)

View file

@ -9,7 +9,10 @@ class PetsController < ApplicationController
# return modeling_disabled unless user_signed_in? && current_user.admin?
raise Pet::PetNotFound unless params[:name]
@pet = Pet.load(params[:name])
@pet = Pet.load(
params[:name],
:item_scope => Item.includes(:translations),
)
points = contribute(current_user, @pet)
respond_to do |format|

View file

@ -3,7 +3,7 @@ class SitemapController < ApplicationController
def index
respond_to do |format|
format.xml { @items = Item.sitemap }
format.xml { @items = Item.includes(:translations).sitemap }
end
end
end

View file

@ -13,8 +13,9 @@ class ClosetHanger < ApplicationRecord
validate :list_belongs_to_user
scope :alphabetical_by_item_name, -> {
i = Item.arel_table
joins(:item).order(i[:name].asc)
it = Item::Translation.arel_table
joins(:item => :translations).where(it[:locale].eq(I18n.locale)).
order(it[:name].asc)
}
scope :trading, -> {
ch = arel_table
@ -85,24 +86,28 @@ class ClosetHanger < ApplicationRecord
base
end
# TODO: Is the performance improvement on this actually much better than just
# `includes`, now that `Item::Translation` records aren't part of it anymore?
def self.preload_items(
hangers,
items_scope: Item.all
items_scope: Item.all,
item_translations_scope: Item::Translation.all
)
# Preload the records we need. (This is like `includes`, but `includes`
# always selects all fields for all records, and we give the caller the
# opportunity to specify which fields it actually wants via scope!)
items = items_scope.where(id: hangers.map(&:item_id))
translations = item_translations_scope.where(item_id: items.map(&:id))
# Group the records by relevant IDs.
translations_by_item_id = translations.group_by(&:item_id)
items_by_id = items.to_h { |i| [i.id, i] }
# Assign the preloaded records to the records they belong to. (This is like
# doing e.g. h.item = ..., but that's a database write - we actually just
# want to set the `item` field itself directly! Hacky, ripped from how
# `ActiveRecord::Associations::Preloader` does it!)
# doing e.g. i.translations = ..., but that's a database write - we
# actually just want to set the `translations` field itself directly!
# Hacky, ripped from how `ActiveRecord::Associations::Preloader` does it!)
items.each do |item|
item.association(:translations).target = translations_by_item_id[item.id]
end
hangers.each do |hanger|
hanger.association(:item).target = items_by_id[hanger.item_id]
end

View file

@ -45,7 +45,8 @@ class ClosetList < ApplicationRecord
def self.preload_items(
lists,
hangers_scope: ClosetHanger.all,
items_scope: Item.all
items_scope: Item.all,
item_translations_scope: Item::Translation.all
)
# Preload the records we need. (This is like `includes`, but `includes`
# always selects all fields for all records, and we give the caller the
@ -56,9 +57,9 @@ class ClosetList < ApplicationRecord
hangers_by_list_id = hangers.group_by(&:list_id)
# Assign the preloaded records to the records they belong to. (This is like
# doing e.g. h.item = ..., but that's a database write - we actually just
# want to set the `item` field itself directly! Hacky, ripped from how
# `ActiveRecord::Associations::Preloader` does it!)
# doing e.g. i.translations = ..., but that's a database write - we
# actually just want to set the `translations` field itself directly!
# Hacky, ripped from how `ActiveRecord::Associations::Preloader` does it!)
lists.each do |list|
list.association(:hangers).target = hangers_by_list_id[list.id]
end
@ -67,6 +68,7 @@ class ClosetList < ApplicationRecord
ClosetHanger.preload_items(
hangers,
items_scope: items_scope,
item_translations_scope: item_translations_scope,
)
end

View file

@ -6,12 +6,7 @@ class Item < ApplicationRecord
SwfAssetType = 'object'
# Keep the reference to the deprecated `Item::Translation` record, but don't
# bind it directly to any attributes anymore. We have some temporary writers
# that hack around the API to keep the attributes synced, while no longer
# reading *from* them by default.
# TODO: Remove once we're all done with translations, both here and in 2020!
translates
translates :name, :description, :rarity
has_many :closet_hangers
has_one :contribution, :as => :contributed, :inverse_of => :contributed
@ -28,6 +23,13 @@ class Item < ApplicationRecord
cattr_reader :per_page
@@per_page = 30
scope :alphabetize_by_translations, ->(locale) {
locale = locale or I18n.locale
it = Item::Translation.arel_table
joins(:translations).where(it[:locale].eq('en')).
order(it[:name].asc)
}
scope :newest, -> {
order(arel_table[:created_at].desc) if arel_table[:created_at]
}
@ -37,10 +39,14 @@ class Item < ApplicationRecord
scope :with_closet_hangers, -> { joins(:closet_hangers) }
scope :name_includes, ->(value, locale = I18n.locale) {
Item.where("name LIKE ?", "%" + sanitize_sql_like(value) + "%")
it = Item::Translation.arel_table
Item.joins(:translations).where(it[:locale].eq(locale)).
where(it[:name].matches('%' + sanitize_sql_like(value) + '%'))
}
scope :name_excludes, ->(value, locale = I18n.locale) {
Item.where("name NOT LIKE ?", "%" + sanitize_sql_like(value) + "%")
it = Item::Translation.arel_table
Item.joins(:translations).where(it[:locale].eq(locale)).
where(it[:name].matches('%' + sanitize_sql_like(value) + '%').not)
}
scope :is_nc, -> {
i = Item.arel_table
@ -51,10 +57,14 @@ class Item < ApplicationRecord
where(i[:rarity_index].in(Item::NCRarities).or(i[:is_manually_nc].eq(true)).not)
}
scope :is_pb, -> {
it = Item::Translation.arel_table
joins(:translations).where(it[:locale].eq('en')).
where('description LIKE ?',
'%' + sanitize_sql_like(PAINTBRUSH_SET_DESCRIPTION) + '%')
}
scope :is_not_pb, -> {
it = Item::Translation.arel_table
joins(:translations).where(it[:locale].eq('en')).
where('description NOT LIKE ?',
'%' + sanitize_sql_like(PAINTBRUSH_SET_DESCRIPTION) + '%')
}
@ -112,30 +122,12 @@ class Item < ApplicationRecord
distinct
}
# Temporary writers to keep the English translation record updated, while
# primarily using the attributes on the model itself.
#
# Once this app and DTI 2020 are both comfortably off the translation system,
# we can remove this!
def name=(new_name)
globalize.write(:en, :name, new_name)
write_attribute(:name, new_name)
end
def description=(new_description)
globalize.write(:en, :description, new_description)
write_attribute(:description, new_description)
end
def rarity=(new_rarity)
globalize.write(:en, :rarity, new_rarity)
write_attribute(:rarity, new_rarity)
end
def nc_trade_value
return nil unless nc?
begin
OwlsValueGuide.find_by_name(name)
OwlsValueGuide.find_by_name(name(:en))
rescue OwlsValueGuide::NotFound => error
Rails.logger.debug("No NC trade value listed for #{name} (#{id})")
Rails.logger.debug("No NC trade value listed for #{name(:en)} (#{id})")
return nil
rescue OwlsValueGuide::NetworkError => error
Rails.logger.error("Couldn't load nc_trade_value: #{error.full_message}")
@ -448,16 +440,16 @@ class Item < ApplicationRecord
species_support_strs = info['species_support'] || []
self.species_support_ids = species_support_strs.map(&:to_i)
self.name = info['name']
self.description = info['description']
self.thumbnail_url = info['thumbnail_url']
self.category = info['category']
self.type = info['type']
self.rarity = info['rarity']
self.rarity_index = info['rarity_index'].to_i
self.price = info['price'].to_i
self.weight_lbs = info['weight_lbs'].to_i
self.zones_restrict = info['zones_restrict']
self.name_translations = {locale => info['name']}
attribute_names.each do |attribute|
next if attribute == 'name'
value = info[attribute.to_sym]
if value
value = value.to_i if value.is_a? Float
self[attribute] = value
end
end
end
def pending_swf_assets

View file

@ -11,7 +11,8 @@ class Item
end
def results
@filters.map(&:to_query).inject(Item.all, &:merge).order(:name)
@filters.map(&:to_query).inject(Item.all, &:merge).
alphabetize_by_translations(Query.locale)
end
def to_s

View file

@ -1,26 +0,0 @@
class AddTranslatedFieldsDirectlyToItems < ActiveRecord::Migration[7.1]
def change
add_column :items, :name, :string, null: false
add_column :items, :description, :text, null: false, default: ""
add_column :items, :rarity, :string, null: false, default: ""
reversible do |direction|
direction.up do
total_count = Item.count
saved_count = 0
Item.includes(:translations).find_in_batches do |items|
Item.transaction do
items.each do |item|
item.name = item.translation_for(:en).name
item.description = item.translation_for(:en).description || ""
item.rarity = item.translation_for(:en).rarity || ""
item.save!
end
saved_count += items.size
puts "Saved #{saved_count} of #{total_count} items"
end
end
end
end
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.1].define(version: 2024_02_20_230420) do
ActiveRecord::Schema[7.1].define(version: 2024_02_03_161355) do
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
t.integer "species_id", null: false
t.integer "color_id", null: false
@ -144,9 +144,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_02_20_230420) do
t.integer "manual_special_color_id"
t.column "modeling_status_hint", "enum('done','glitchy')"
t.boolean "is_manually_nc", default: false, null: false
t.string "name", null: false
t.text "description", default: "", null: false
t.string "rarity", default: "", null: false
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"
t.index ["modeling_status_hint", "id"], name: "items_modeling_status_hint_and_id"