Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/controllers/search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ def index

records = records.limit(25)

render json: records.map(&:remote_search_label)
labels = records.map(&:remote_search_label)
labels = model_class.resolve_duplicate_labels(labels) if model_class.respond_to?(:resolve_duplicate_labels)

render json: labels
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like this, @jmilljr24 ?

end

private
Expand Down
15 changes: 15 additions & 0 deletions app/models/workshop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,21 @@ def attach_assets_from_idea!

remote_searchable_by :title

def self.remote_search(query)
super.includes(:windows_type)
end

def remote_search_label
label = windows_type ? "#{title} (#{windows_type.short_name})" : title
{ id: id, label: label }
end

def self.resolve_duplicate_labels(labels)
dupes = labels.group_by { |l| l[:label] }.select { |_, v| v.size > 1 }.keys.to_set
labels.each { |l| l[:label] = "#{l[:label]} ##{l[:id]}" if dupes.include?(l[:label]) }
labels
end

Copy link
Collaborator Author

@maebeale maebeale Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update workshop-specific remote search label display. and conditionally show workshop #ID if there are two workshops w same name AND windows type short name (there are many of these rn in prod dataset)

private

def assign_pending_associations
Expand Down
2 changes: 1 addition & 1 deletion app/views/stories/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

<div class="flex-1 mb-4 md:mb-0">
<%= f.input :workshop_id,
collection: f.object.workshop.present? ? [[ f.object.workshop.title, f.object.workshop.id ]] : [],
collection: f.object.workshop.present? ? [[ f.object.workshop.remote_search_label[:label], f.object.workshop.id ]] : [],
include_blank: true,
input_html: {
class: "w-full px-3 py-2 border border-gray-300 rounded-lg",
Expand Down
2 changes: 1 addition & 1 deletion app/views/story_ideas/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
</div>
<div class="flex-1 mb-4 md:mb-0">
<%= f.input :workshop_id,
collection: f.object.workshop.present? ? [[ f.object.workshop.title, f.object.workshop.id]] : [],
collection: f.object.workshop.present? ? [[ f.object.workshop.remote_search_label[:label], f.object.workshop.id]] : [],
include_blank: true,
required: true,
input_html: {
Expand Down
2 changes: 1 addition & 1 deletion app/views/workshop_logs/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<div class="flex flex-col md:flex-row md:space-x-4 mb-6">
<div class="flex-1 mb-4 md:mb-0">
<%= f.input :workshop_id,
collection: f.object.workshop.present? ? [[ f.object.workshop.title, f.object.workshop.id]] : [],
collection: f.object.workshop.present? ? [[ f.object.workshop.remote_search_label[:label], f.object.workshop.id]] : [],
include_blank: true,
required: true,
input_html: {
Expand Down
2 changes: 1 addition & 1 deletion app/views/workshop_variation_ideas/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div>
<%= f.input :workshop_id,
collection: f.object.workshop.present? ? [[ f.object.workshop.title, f.object.workshop.id]] : [],
collection: f.object.workshop.present? ? [[ f.object.workshop.remote_search_label[:label], f.object.workshop.id]] : [],
include_blank: true,
required: true,
input_html: {
Expand Down
2 changes: 1 addition & 1 deletion app/views/workshop_variations/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</div>
<% else %>
<%= f.input :workshop_id,
collection: f.object.workshop.present? ? [[ f.object.workshop.title, f.object.workshop.id]] : [],
collection: f.object.workshop.present? ? [[ f.object.workshop.remote_search_label[:label], f.object.workshop.id]] : [],
include_blank: true,
required: true,
input_html: {
Expand Down
2 changes: 1 addition & 1 deletion app/views/workshops/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<%= link_to "Workshops", workshops_path, class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %>
<%= link_to "View", workshop_path(@workshop), class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %>
</div>
<h1 class="text-2xl font-semibold text-gray-900 mb-4">Edit workshop</h1>
<h1 class="text-2xl font-semibold text-gray-900 mb-4">Edit workshop: <%= @workshop.remote_search_label[:label] %></h1>

<div class="border-b border-gray-300 mb-6"></div>

Expand Down
28 changes: 28 additions & 0 deletions db/seeds/dummy_dev_seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,34 @@
Workshop.where(title: workshop_data[:title]).first_or_create!(workshop_data)
end

# Duplicate-title workshops to exercise ID disambiguation in search
[
{
title: "Healing Through Color",
windows_type: adult_wt,
full_name: "Maria Torres",
month: 3,
year: 2020,
description: "Uses color mixing and painting to help participants explore emotions and find calm. Participants create a personal color wheel that maps feelings to colors.",
published: true,
searchable: true,
created_by: admin_user
},
{
title: "Healing Through Color",
windows_type: adult_wt,
full_name: "James Whitfield",
month: 9,
year: 2022,
description: "A revised version exploring color as a pathway to emotional awareness. Participants blend watercolors while discussing how color connects to memory and healing.",
published: true,
searchable: true,
created_by: admin_user
}
].each do |workshop_data|
Workshop.create!(workshop_data)
end

puts "Assigning workshop categories and sectors…"
workshops = Workshop.all
categories = Category.all.to_a
Expand Down
63 changes: 63 additions & 0 deletions spec/models/workshop_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,68 @@
end
end

describe "#remote_search_label" do
it "returns title with windows type short_name" do
record = create(:workshop, title: "Art Therapy", windows_type: create(:windows_type, :children))

expect(record.remote_search_label).to eq({ id: record.id, label: "Art Therapy (CHILDREN)" })
end

it "returns just the title when no windows type" do
record = create(:workshop, title: "Art Therapy", windows_type: nil)

expect(record.remote_search_label).to eq({ id: record.id, label: "Art Therapy" })
end
end

describe ".resolve_duplicate_labels" do
it "omits id when labels are unique" do
wt = create(:windows_type, :adult)
w1 = create(:workshop, title: "Art Therapy", windows_type: wt)
w2 = create(:workshop, title: "Music Therapy", windows_type: wt)

labels = Workshop.resolve_duplicate_labels([ w1, w2 ].map(&:remote_search_label))

expect(labels).to contain_exactly(
{ id: w1.id, label: "Art Therapy (ADULT)" },
{ id: w2.id, label: "Music Therapy (ADULT)" }
)
end

it "appends id only to duplicate labels" do
wt = create(:windows_type, :adult)
w1 = create(:workshop, title: "Art Therapy", windows_type: wt)
w2 = create(:workshop, title: "Art Therapy", windows_type: wt)
w3 = create(:workshop, title: "Music Therapy", windows_type: wt)

labels = Workshop.resolve_duplicate_labels([ w1, w2, w3 ].map(&:remote_search_label))

expect(labels).to contain_exactly(
{ id: w1.id, label: "Art Therapy (ADULT) ##{w1.id}" },
{ id: w2.id, label: "Art Therapy (ADULT) ##{w2.id}" },
{ id: w3.id, label: "Music Therapy (ADULT)" }
)
end
end

describe ".remote_search" do
it "finds workshops matching the query" do
matching = create(:workshop, title: "Healing Through Art")
create(:workshop, title: "Unrelated Workshop")

results = Workshop.remote_search("Healing")

expect(results).to contain_exactly(matching)
end

it "eager loads windows_type to avoid N+1" do
create(:workshop, title: "Healing Through Art")

results = Workshop.remote_search("Healing")

expect(results.includes_values).to include(:windows_type)
end
end

# Add tests for scopes, methods like #rating, #log_count, SearchCop etc.
end
Loading