forked from OpenNeo/impress
Emi Matchu
583f3c712f
Okay, so I still don't know why rendering is just so slow (though migrating away from item translations did help!), but I can at least cache entire closet lists as a basic measure. That way, the first user to see the latest version of a closet list will still need just as much time to load it… but *only* the ones that have changed since last time (rather than always the full page), and then subsequent users get to reuse it too! Should help a lot for high-traffic lists, which incidentally are likely to be the big ones belonging to highly active traders! One big change we needed to make was to extract the `user-owns` and `user-wants` classes (which we use for trade matches for *the user viewing the list right now*) out of the cached HTML, and apply them after with Javascript instead. I always dislike moving stuff to JS, but the wins here seem. truly very very good, all things considered!
276 lines
8.6 KiB
Ruby
276 lines
8.6 KiB
Ruby
class ClosetHangersController < ApplicationController
|
|
before_action :authorize_user!, :only => [:destroy, :create, :update, :update_quantities, :petpage]
|
|
before_action :find_item, :only => [:create, :update_quantities]
|
|
before_action :find_user, :only => [:index, :petpage, :update_quantities]
|
|
|
|
def destroy
|
|
if params[:list_id]
|
|
@closet_list = current_user.find_closet_list_by_id_or_null_owned params[:list_id]
|
|
@closet_list.hangers.destroy_all
|
|
respond_to do |format|
|
|
format.html {
|
|
flash[:notice] = t("closet_hangers.destroy_all.success")
|
|
redirect_back!(user_closet_hangers_path(current_user))
|
|
}
|
|
|
|
format.json { render :json => true }
|
|
end
|
|
elsif params[:ids]
|
|
ClosetHanger.transaction do
|
|
current_user.closet_hangers.where(id: params[:ids]).destroy_all
|
|
end
|
|
render json: true
|
|
else
|
|
@closet_hanger = current_user.closet_hangers.find params[:id]
|
|
@closet_hanger.destroy
|
|
@item = @closet_hanger.item
|
|
closet_hanger_destroyed
|
|
end
|
|
end
|
|
|
|
def index
|
|
is_user = user_signed_in? && current_user == @user
|
|
@public_perspective = params.has_key?(:public) || !is_user
|
|
@perspective_user = current_user unless @public_perspective
|
|
closet_lists = @user.closet_lists
|
|
unless @perspective_user == @user
|
|
# If we run this when the user matches, we'll end up with effectively:
|
|
# WHERE belongs_to_user AND (is_public OR belongs_to_user)
|
|
# and it's a bit silly to put the SQL server through a condition that's
|
|
# always true.
|
|
closet_lists = closet_lists.visible_to(@perspective_user)
|
|
end
|
|
@closet_lists_by_owned = find_closet_lists_by_owned(closet_lists)
|
|
|
|
visible_groups = @user.closet_hangers_groups_visible_to(@perspective_user)
|
|
@unlisted_closet_hangers_by_owned = find_unlisted_closet_hangers_by_owned(visible_groups)
|
|
|
|
@items = []
|
|
|
|
@closet_lists_by_owned.each do |owned, lists|
|
|
lists.each do |list|
|
|
list.hangers.each do |hanger|
|
|
@items << hanger.item
|
|
end
|
|
end
|
|
end
|
|
|
|
@unlisted_closet_hangers_by_owned.each do |owned, hangers|
|
|
hangers.each do |hanger|
|
|
@items << hanger.item
|
|
end
|
|
end
|
|
|
|
if @public_perspective && user_signed_in?
|
|
current_user.assign_closeted_to_items!(@items)
|
|
end
|
|
|
|
@campaign = Fundraising::Campaign.current
|
|
end
|
|
|
|
def petpage
|
|
# Find all closet lists, and also the hangers of the visible closet lists
|
|
closet_lists = @user.closet_lists.select([
|
|
:id, :name, :hangers_owned, :description]).alphabetical
|
|
if params[:filter]
|
|
# If user specified which lists should be visible, restrict to those
|
|
if params[:lists] && params[:lists].respond_to?(:keys)
|
|
visible_closet_lists = closet_lists.where(:id => params[:lists].keys)
|
|
else
|
|
visible_closet_lists = []
|
|
end
|
|
else
|
|
# Otherwise, default to public lists
|
|
visible_closet_lists = closet_lists.publicly_visible
|
|
end
|
|
@closet_lists_by_owned = closet_lists.group_by(&:hangers_owned)
|
|
@visible_closet_lists_by_owned = find_closet_lists_by_owned(visible_closet_lists)
|
|
|
|
# Find which groups (own/want) should be visible
|
|
if params[:filter]
|
|
# If user specified which groups should be visible, restrict to those
|
|
# (must be either true or false)
|
|
@visible_groups = []
|
|
if params[:groups] && params[:groups].respond_to?(:keys)
|
|
@visible_groups << true if params[:groups].keys.include?('true')
|
|
@visible_groups << false if params[:groups].keys.include?('false')
|
|
end
|
|
else
|
|
# Otherwise, default to public groups
|
|
@visible_groups = @user.public_closet_hangers_groups
|
|
end
|
|
|
|
@visible_unlisted_closet_hangers_by_owned =
|
|
find_unlisted_closet_hangers_by_owned(@visible_groups)
|
|
end
|
|
|
|
def create
|
|
@closet_hanger = current_user.closet_hangers.build(closet_hanger_params)
|
|
@closet_hanger.item = @item
|
|
|
|
if @closet_hanger.save
|
|
closet_hanger_saved
|
|
else
|
|
closet_hanger_invalid
|
|
end
|
|
end
|
|
|
|
def update
|
|
if params[:ids]
|
|
ClosetHanger.transaction do
|
|
@closet_hangers = current_user.closet_hangers.includes(:list).find params[:ids]
|
|
@closet_hangers.each do |h|
|
|
h.possibly_null_list_id = params[:list_id]
|
|
h.save!
|
|
end
|
|
end
|
|
redirect_back!(user_closet_hangers_path(current_user))
|
|
else
|
|
@closet_hanger = current_user.closet_hangers.find(params[:id])
|
|
@closet_hanger.attributes = closet_hanger_params
|
|
@item = @closet_hanger.item
|
|
|
|
unless @closet_hanger.quantity == 0 # save the hanger, new record or not
|
|
if @closet_hanger.save
|
|
closet_hanger_saved
|
|
else
|
|
closet_hanger_invalid
|
|
end
|
|
else # delete the hanger since the user doesn't want it
|
|
@closet_hanger.destroy
|
|
closet_hanger_destroyed
|
|
end
|
|
end
|
|
end
|
|
|
|
def update_quantities
|
|
begin
|
|
ClosetHanger.transaction do
|
|
params[:quantity].each do |key, quantity|
|
|
ClosetHanger.set_quantity!(quantity, :user_id => @user.id,
|
|
:item_id => @item.id, :key => key)
|
|
end
|
|
flash[:notice] = t('closet_hangers.update_quantities.success',
|
|
:item_name => @item.name)
|
|
end
|
|
rescue ActiveRecord::RecordInvalid => e
|
|
flash[:alert] = t('closet_hangers.update_quantities.invalid',
|
|
:errors => e.message)
|
|
end
|
|
redirect_to @item
|
|
end
|
|
|
|
private
|
|
|
|
def closet_hanger_params
|
|
params.require(:closet_hanger).permit(:list_id, :owned, :quantity)
|
|
end
|
|
|
|
def closet_hanger_destroyed
|
|
respond_to do |format|
|
|
format.html {
|
|
ownership_key = @closet_hanger.owned? ? 'owned' : 'wanted'
|
|
flash[:notice] = t("closet_hangers.destroy.success.#{ownership_key}",
|
|
:item_name => @item.name)
|
|
redirect_back!(@item)
|
|
}
|
|
|
|
format.json { render :json => true }
|
|
end
|
|
end
|
|
|
|
def closet_hanger_invalid
|
|
respond_to do |format|
|
|
format.html {
|
|
ownership_key = @closet_hanger.owned? ? 'owned' : 'wanted'
|
|
flash[:alert] = t("closet_hangers.create.invalid.#{ownership_key}",
|
|
:item_name => @item.name,
|
|
:errors => @closet_hanger.errors.full_messages.to_sentence)
|
|
redirect_back!(@item)
|
|
}
|
|
|
|
format.json { render :json => {:errors => @closet_hanger.errors.full_messages}, :status => :unprocessable_entity }
|
|
end
|
|
end
|
|
|
|
def closet_hanger_saved
|
|
respond_to do |format|
|
|
format.html {
|
|
ownership_key = @closet_hanger.owned? ? 'owned' : 'wanted'
|
|
if @closet_hanger.list
|
|
flash[:notice] = t("closet_hangers.create.success.#{ownership_key}.in_list",
|
|
:item_name => @item.name,
|
|
:list_name => @closet_hanger.list.name,
|
|
:count => @closet_hanger.quantity)
|
|
else
|
|
flash[:notice] = t("closet_hangers.create.success.#{ownership_key}.unlisted",
|
|
:item_name => @item.name,
|
|
:count => @closet_hanger.quantity)
|
|
end
|
|
redirect_back!(@item)
|
|
}
|
|
|
|
format.json { render :json => true }
|
|
end
|
|
end
|
|
|
|
def find_item
|
|
@item = Item.find params[:item_id]
|
|
end
|
|
|
|
def find_user
|
|
if params[:user_id]
|
|
@user = User.find params[:user_id]
|
|
elsif user_signed_in?
|
|
redirect_to user_closet_hangers_path(current_user)
|
|
else
|
|
redirect_to new_auth_user_session_path(:return_to => request.fullpath)
|
|
end
|
|
end
|
|
|
|
def find_closet_lists_by_owned(lists_scope)
|
|
return {} if lists_scope == []
|
|
lists = lists_scope.alphabetical
|
|
ClosetList.preload_items(
|
|
lists,
|
|
hangers_scope: hangers_scope,
|
|
items_scope: items_scope,
|
|
)
|
|
lists.group_by(&:hangers_owned)
|
|
end
|
|
|
|
def find_unlisted_closet_hangers_by_owned(visible_groups)
|
|
unless visible_groups.empty?
|
|
hangers = @user.closet_hangers.unlisted.
|
|
owned_before_wanted.alphabetical_by_item_name.
|
|
where(:owned => [visible_groups])
|
|
ClosetHanger.preload_items(
|
|
hangers,
|
|
items_scope: items_scope,
|
|
)
|
|
hangers.group_by(&:owned)
|
|
else
|
|
{}
|
|
end
|
|
end
|
|
|
|
def hangers_scope
|
|
ClosetHanger.select(:id, :item_id, :list_id, :quantity)
|
|
end
|
|
|
|
def items_scope
|
|
Item.select(:id, :name, :description, :thumbnail_url, :rarity_index,
|
|
:is_manually_nc)
|
|
end
|
|
|
|
def owned
|
|
owned = true
|
|
if closet_hanger_params
|
|
owned = case closet_hanger_params[:owned]
|
|
when 'true', '1' then true
|
|
when 'false', '0' then false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|