[WV2] Switch search to text-based filter syntax

Replace the structured search filter approach with from_text(), enabling
the full search syntax (is:nc, occupies:background, user:owns, etc.) in
a single text field.

Changes:
- Search form now uses single `q` text param instead of `q[name]`
- Controller uses Item::Search::Query.from_text instead of from_params
- Auto-fit filter applied via .merge(Item.fits(body_id)) in controller
- Added error handling for Item::Search::Error
- Updated pagination param from `q[page]` to `page`
- Removed build_search_filters method (no longer needed)
- Fixed outfit_state_params helper to handle q as string

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Emi Matchu 2026-02-15 21:03:18 -08:00
parent ff7c590790
commit 4f2691ef43
4 changed files with 25 additions and 63 deletions

View file

@ -99,17 +99,23 @@ class WardrobeController < ApplicationController
# Handle search mode
@search_mode = params[:q].present?
if @search_mode
search_filters = build_search_filters(params[:q], @outfit)
query_params = ActionController::Parameters.new(
search_filters.each_with_index.map { |filter, i| [i.to_s, filter] }.to_h
)
@query = Item::Search::Query.from_params(query_params, current_user)
@search_results = @query.results.paginate(page: params.dig(:q, :page), per_page: 30)
begin
@query = Item::Search::Query.from_text(params[:q], current_user)
results = @query.results
# Load appearances for search results to get zone information
target = @alt_style || @pet_type
if target
@appearances_by_item_id = Item.appearances_for(@search_results, target, swf_asset_includes: [:zone])
# Auto-fit filter: apply body_id filter from outfit state
body_id = @outfit.alt_style&.body_id || @outfit.pet_type&.body_id
results = results.merge(Item.fits(body_id)) if body_id
@search_results = results.paginate(page: params[:page], per_page: 30)
# Load appearances for search results to get zone information
target = @alt_style || @pet_type
if target
@appearances_by_item_id = Item.appearances_for(@search_results, target, swf_asset_includes: [:zone])
end
rescue Item::Search::Error => e
@search_error = e.message
end
end
@ -152,51 +158,4 @@ class WardrobeController < ApplicationController
def outfit_state_params_present?
params[:species].present? || params[:color].present? || params[:objects].present? || params[:closet].present?
end
def build_search_filters(query_params, outfit)
filters = []
# Add name filter if present
if query_params[:name].present?
filters << { key: "name", value: query_params[:name] }
end
# Add item kind filter if present
if query_params[:item_kind].present?
case query_params[:item_kind]
when "nc"
filters << { key: "is_nc", value: "true" }
when "np"
filters << { key: "is_np", value: "true" }
when "pb"
filters << { key: "is_pb", value: "true" }
end
end
# Add zone filter if present
if query_params[:zone].present?
filters << { key: "occupied_zone_set_name", value: query_params[:zone] }
end
# Always add auto-filter for items that fit the current pet
pet_type = outfit.pet_type
if pet_type
fit_filter = {
key: "fits",
value: {
species_id: pet_type.species_id.to_s,
color_id: pet_type.color_id.to_s
}
}
# Include alt_style_id if present
if outfit.alt_style_id.present?
fit_filter[:value][:alt_style_id] = outfit.alt_style_id.to_s
end
filters << fit_filter
end
filters
end
end

View file

@ -24,8 +24,8 @@ module WardrobeHelper
end
unless except.include?(:q)
(params[:q] || {}).each do |key, value|
fields << hidden_field_tag("q[#{key}]", value) if value.present?
if params[:q].present?
fields << hidden_field_tag(:q, params[:q])
end
end

View file

@ -1,13 +1,16 @@
.search-results
- if @search_results.any?
= will_paginate @search_results, page_links: false, param_name: "q[page]", params: @outfit.wardrobe_params.merge(q: params[:q])
- if @search_error
.error-state
%p.error-message= @search_error
- elsif @search_results.any?
= will_paginate @search_results, page_links: false, param_name: :page, params: @outfit.wardrobe_params.merge(q: params[:q])
%ul.search-results-list
- @search_results.each do |item|
- appearance = @appearances_by_item_id&.dig(item.id)
= render "items/item_card", item: item, appearance: appearance
= will_paginate @search_results, param_name: "q[page]", params: @outfit.wardrobe_params.merge(q: params[:q])
= will_paginate @search_results, param_name: :page, params: @outfit.wardrobe_params.merge(q: params[:q])
- else
.empty-state

View file

@ -59,7 +59,7 @@
= outfit_state_params except: [:q]
= form_with url: @wardrobe_path, method: :get, class: "search-form" do |f|
= outfit_state_params
= f.text_field "q[name]", placeholder: "Search for items...", value: params.dig(:q, :name), "aria-label": "Search for items"
= f.text_field :q, placeholder: "Search items… (try is:nc, occupies:hat, user:owns)", value: params[:q], "aria-label": "Search for items"
= f.submit "Search"
- if @search_mode