Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion app/controllers/search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def index

records = records.limit(25)

render json: records.map(&:remote_search_label)
render json: model_class.remote_search_labels(records)
Comment thread
jmilljr24 marked this conversation as resolved.
Outdated
end

private
Expand Down
4 changes: 4 additions & 0 deletions app/models/concerns/remote_searchable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ def remote_search_columns
@remote_search_columns || []
end

def remote_search_labels(records)
records.map(&:remote_search_label)
end

def remote_search(query)
return none if query.blank?
raise "remote_searchable_by not defined for #{name}" if remote_search_columns.empty?
Expand Down
16 changes: 16 additions & 0 deletions app/models/workshop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,22 @@ 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.remote_search_labels(records)
labels = records.map(&:remote_search_label)
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
Copy Markdown
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 ".remote_search_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.remote_search_labels([ w1, w2 ])

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.remote_search_labels([ w1, w2, w3 ])

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