diff --git a/app/models/item.rb b/app/models/item.rb index 6a5febcf..095340b3 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -82,14 +82,16 @@ class Item < ActiveRecord::Base joins(:swf_assets).where(sa[:zone_id].in(zone_ids)).distinct } scope :not_occupies, ->(zone_label, locale = I18n.locale) { - # TODO: The perf on this is miserable on its own, the query plan chooses - # a bad index for the join on parents_swf_assets here (but not in the - # `occupies` scope?) and I don't know why! But it makes a better plan when - # combined with `name_includes` so this is probably fine in practice? + # TODO: This is pretty slow! But I imagine it's uncommon so that's probably + # fine in practice? Querying for "has NO records matching X" is hard! zone_ids = Zone.matching_label(zone_label, locale).map(&:id) i = Item.arel_table sa = SwfAsset.arel_table - joins(:swf_assets).where(sa[:zone_id].not_in(zone_ids)).distinct + psa = ParentSwfAssetRelationship.arel_table + subquery = SwfAsset.select('COUNT(*)').joins(:parent_swf_asset_relationships). + where(psa[:parent_type].eq('Item')).where(psa[:parent_id].eq(i[:id])). + where(sa[:zone_id].in(zone_ids)) + where("(#{subquery.to_sql}) = 0") } scope :restricts, ->(zone_label, locale = I18n.locale) { zone_ids = Zone.matching_label(zone_label, locale).map(&:id) diff --git a/app/models/swf_asset.rb b/app/models/swf_asset.rb index e8b4ca78..1a9be536 100644 --- a/app/models/swf_asset.rb +++ b/app/models/swf_asset.rb @@ -29,6 +29,7 @@ class SwfAsset < ActiveRecord::Base converts_swfs :size => IMAGE_SIZES[:large], :output_sizes => IMAGE_SIZES.values belongs_to :zone + has_many :parent_swf_asset_relationships scope :includes_depth, -> { includes(:zone) }