diff --git a/app/controllers/concerns/ahoy_tracking.rb b/app/controllers/concerns/ahoy_tracking.rb index f74a1e771..cbc7441da 100644 --- a/app/controllers/concerns/ahoy_tracking.rb +++ b/app/controllers/concerns/ahoy_tracking.rb @@ -14,7 +14,7 @@ def track_index_intent(resource_class, scope, params) if scope.respond_to?(:total_entries) # will_paginate scope.total_entries elsif scope.respond_to?(:count) - count = scope.count + count = scope.unscope(:select).count count.is_a?(Hash) ? count.size : count else 0 diff --git a/app/controllers/workshops_controller.rb b/app/controllers/workshops_controller.rb index 01fbcf61a..3d17352c7 100644 --- a/app/controllers/workshops_controller.rb +++ b/app/controllers/workshops_controller.rb @@ -4,8 +4,8 @@ class WorkshopsController < ApplicationController def index authorize! - @category_types = CategoryType.published.order(:name).decorate - @sectors = Sector.published + @category_types = CategoryType.published.where(story_specific: false).order(:name).decorate + @sectors = Sector.published.order(:name) @windows_types = WindowsType.all if turbo_frame_request? @@ -21,6 +21,7 @@ def index render :workshop_results else + @sort = params[:sort].presence || "title" render :index end end diff --git a/app/frontend/javascript/controllers/collection_controller.js b/app/frontend/javascript/controllers/collection_controller.js index a9faf4c0b..bb43eaa1e 100644 --- a/app/frontend/javascript/controllers/collection_controller.js +++ b/app/frontend/javascript/controllers/collection_controller.js @@ -67,6 +67,7 @@ export default class extends Controller { input.checked = false; }); // this.element.reset(); + this.element.reset(); this.submitForm(); } diff --git a/app/services/workshop_search_service.rb b/app/services/workshop_search_service.rb index e34c93280..2b8f7a5c8 100644 --- a/app/services/workshop_search_service.rb +++ b/app/services/workshop_search_service.rb @@ -29,7 +29,7 @@ def call # Compute the effective sort def default_sort - params[:sort].presence || "created" + params[:sort].presence || "title" # return params[:sort] if params[:sort].present? # return 'keywords' if params[:query].present? # only when returning weighted results from # search_by_query # 'title' diff --git a/app/views/workshops/_filters.html.erb b/app/views/workshops/_filters.html.erb index 9dc442319..924e40804 100644 --- a/app/views/workshops/_filters.html.erb +++ b/app/views/workshops/_filters.html.erb @@ -24,6 +24,13 @@
+ <%= render "dropdown_filter", + dom_id_prefix: "windows-types", + label_text: "Windows Audience", + items: @windows_types, + label_method: :short_name, + param_name: :windows_types %> + <%= render "categories_fields", category_types: @category_types %> <%= render "dropdown_filter", @@ -32,12 +39,5 @@ items: @sectors.reject { |sector| sector.name == "Other" }, param_name: :sectors %> - <%= render "dropdown_filter", - dom_id_prefix: "windows-types", - label_text: "Windows Type", - items: @windows_types, - label_method: :short_name, - param_name: :windows_types %> - <%= render "inactive_fields" if allowed_to?(:manage?, Workshop) %>
diff --git a/app/views/workshops/_sort_by_options.html.erb b/app/views/workshops/_sort_by_options.html.erb index d98edb890..4a4707faa 100644 --- a/app/views/workshops/_sort_by_options.html.erb +++ b/app/views/workshops/_sort_by_options.html.erb @@ -1,7 +1,7 @@
diff --git a/db/migrate/20260216231506_add_not_null_constraints_to_affiliations.rb b/db/migrate/20260216231506_add_not_null_constraints_to_affiliations.rb new file mode 100644 index 000000000..03db06f2f --- /dev/null +++ b/db/migrate/20260216231506_add_not_null_constraints_to_affiliations.rb @@ -0,0 +1,28 @@ +class AddNotNullConstraintsToAffiliations < ActiveRecord::Migration[8.1] + def up + # Clean up any orphaned records before adding constraints + Affiliation.where(organization_id: nil).destroy_all + Affiliation.where(person_id: nil).destroy_all + + change_column_null :affiliations, :organization_id, false + change_column_null :affiliations, :person_id, false + + # Fix column type so foreign key can be added (people.id is int, not bigint) + change_column :affiliations, :person_id, :integer, null: false + + unless foreign_key_exists?(:affiliations, :people, column: :person_id) + add_foreign_key :affiliations, :people, column: :person_id + end + end + + def down + change_column_null :affiliations, :organization_id, true + change_column_null :affiliations, :person_id, true + + if foreign_key_exists?(:affiliations, :people, column: :person_id) + remove_foreign_key :affiliations, :people, column: :person_id + end + + change_column :affiliations, :person_id, :bigint + end +end diff --git a/db/schema.rb b/db/schema.rb index 033518e80..068772f11 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_02_16_120927) do +ActiveRecord::Schema[8.1].define(version: 2026_02_16_231506) do create_table "action_text_mentions", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "action_text_rich_text_id", null: false t.datetime "created_at", null: false diff --git a/spec/models/affiliation_spec.rb b/spec/models/affiliation_spec.rb index 4f1002993..5cec19a27 100644 --- a/spec/models/affiliation_spec.rb +++ b/spec/models/affiliation_spec.rb @@ -11,7 +11,7 @@ build(:affiliation, organization: create(:organization), person: create(:person)) end it { should validate_presence_of(:organization_id) } - it { should belong_to(:person) } + # it { should validate_presence_of(:person_id) } # we needed to not have this to support nested attrs end describe 'enums' do diff --git a/spec/services/workshop_search_service_spec.rb b/spec/services/workshop_search_service_spec.rb index 80a9afade..cb6549b0e 100644 --- a/spec/services/workshop_search_service_spec.rb +++ b/spec/services/workshop_search_service_spec.rb @@ -49,6 +49,41 @@ end end + context "sorting by title ignores punctuation" do + let!(:hyphenated) { create(:workshop, :published, title: "Self-Care Workshop") } + let!(:spaced) { create(:workshop, :published, title: "Self Care Zen") } + let!(:quoted) { create(:workshop, :published, title: '"I Am" Mandalas') } + let!(:numbered) { create(:workshop, :published, title: "100 New Ideas") } + let!(:lowercase) { create(:workshop, :published, title: "a lowercase title") } + + it "sorts case-insensitively" do + service = WorkshopSearchService.new({ sort: "title" }, user: user).call + titles = service.workshops.map(&:title) + + lowercase_idx = titles.index("a lowercase title") + b_workshop_idx = titles.index("B Workshop") + expect(lowercase_idx).to be < b_workshop_idx + end + + it "sorts numbers before letters" do + service = WorkshopSearchService.new({ sort: "title" }, user: user).call + titles = service.workshops.map(&:title) + + numbered_idx = titles.index("100 New Ideas") + quoted_idx = titles.index('"I Am" Mandalas') + expect(numbered_idx).to be < quoted_idx + end + + it "sorts hyphenated and spaced titles adjacently" do + service = WorkshopSearchService.new({ sort: "title" }, user: user).call + titles = service.workshops.map(&:title) + + care_idx = titles.index("Self-Care Workshop") + zen_idx = titles.index("Self Care Zen") + expect((care_idx - zen_idx).abs).to eq(1) + end + end + context "sorting by led" do it "orders descending by led_count then title" do service = WorkshopSearchService.new({ sort: 'led' }, user: user).call @@ -125,9 +160,9 @@ expect(service.sort).to eq('keywords') end - it "defaults to created if no query or sort is provided" do + it "defaults to title if no query or sort is provided" do service = WorkshopSearchService.new({}, user: user).call - expect(service.sort).to eq('created') + expect(service.sort).to eq('title') end end diff --git a/spec/system/workshops_spec.rb b/spec/system/workshops_spec.rb index a0fbf8f93..38c76cd18 100644 --- a/spec/system/workshops_spec.rb +++ b/spec/system/workshops_spec.rb @@ -36,7 +36,7 @@ fill_in 'query', with: 'best workshop' # Open the dropdown - click_on "Windows Type" # this clicks the