From 7a1462b3f2f8b4ef00ec65f494f1a11e53d7776c Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 18:23:16 +0900 Subject: [PATCH 01/22] Unused variable --- app/controllers/concerns/activate_navigation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 3fd6d0464..7d72792f4 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -24,7 +24,7 @@ def initialize_nav return if @active_nav_key || @active_subnav_key @active_nav_key, subnav_map = find_first(nav_item_map) - @active_subnav_key, nop = find_first(subnav_map) + @active_subnav_key, _ = find_first(subnav_map) end def find_first(item_map) From 2bbd83cb73d0341f707e15c6d49c41c6fc6af221 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 18:24:55 +0900 Subject: [PATCH 02/22] Prefer case + when over if + is_a? --- app/controllers/concerns/activate_navigation.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 7d72792f4..3da4f3538 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -36,16 +36,14 @@ def find_first(item_map) end def match?(paths) - if paths.is_a?(String) + case paths + when String paths == request.path - - elsif paths.is_a?(Regexp) + when Regexp paths =~ request.path - - elsif paths.is_a?(Array) - paths.any?{|p| match?(p) } - - elsif paths.is_a?(Hash) + when Array + paths.any? { |p| match?(p) } + when Hash find_first(paths).present? end end From bfb549aec16810d53502343fb0f3e91fddc02b3f Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 18:29:35 +0900 Subject: [PATCH 03/22] exact_path => path_for to be clearer about what it returns. --- .../concerns/activate_navigation.rb | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 3da4f3538..ca06f36db 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -65,14 +65,14 @@ def nav_item_map def event_subnav_item_map @event_subnav_item_map ||= { - 'event-staff-dashboard-link' => exact_path(current_event, :staff), + 'event-staff-dashboard-link' => path_for(current_event, :staff), 'event-staff-info-link' => [ - exact_path(:info, current_event, :staff), - exact_path(:edit, current_event, :staff) + path_for(:info, current_event, :staff), + path_for(:edit, current_event, :staff) ], - 'event-staff-teammates-link' => exact_path(current_event, :staff, Teammate), - 'event-staff-config-link' => exact_path(:config, current_event, :staff), - 'event-staff-guidelines-link' => exact_path(current_event, :staff, :guidelines), + 'event-staff-teammates-link' => path_for(current_event, :staff, Teammate), + 'event-staff-config-link' => path_for(:config, current_event, :staff), + 'event-staff-guidelines-link' => path_for(current_event, :staff, :guidelines), 'event-staff-speaker-emails-link' => starts_with_path(current_event, :staff, :speaker_email_templates), } end @@ -80,7 +80,7 @@ def event_subnav_item_map def website_subnav_item_map @website_subnav_item_map ||= { 'event-website-configuration-link' => starts_with_path(current_event, :staff, :website), - 'event-pages-link' => exact_path(current_event, :staff, Page) + 'event-pages-link' => path_for(current_event, :staff, Page) } end @@ -105,18 +105,18 @@ def program_subnav_item_map def schedule_subnav_item_map @schedule_subnav_item_map ||= { - 'event-schedule-time-slots-link' => exact_path(current_event, :staff, :schedule, TimeSlot), - 'event-schedule-rooms-link' => exact_path(current_event, :staff, :schedule, Room), - 'event-schedule-grid-link' => exact_path(current_event, :staff, :schedule, :grid) + 'event-schedule-time-slots-link' => path_for(current_event, :staff, :schedule, TimeSlot), + 'event-schedule-rooms-link' => path_for(current_event, :staff, :schedule, Room), + 'event-schedule-grid-link' => path_for(current_event, :staff, :schedule, :grid) } end - def exact_path(*args) + def path_for(*args) url_for(args << {only_path: true}) unless args.include?(nil) # don't generate the path unless all dependencies are present end def starts_with_path(sym, *deps) - starts_with = exact_path(sym, *deps) + starts_with = path_for(sym, *deps) Regexp.new(Regexp.escape(starts_with) + ".*") if starts_with end end From 7c3f18ef46d2f355ac1dcedc00593808c79d9f61 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 18:36:10 +0900 Subject: [PATCH 04/22] starts_with_path => path_prefix because it returns a Regexp for matching path prefixes. --- .../concerns/activate_navigation.rb | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index ca06f36db..3904955a0 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -51,11 +51,11 @@ def match?(paths) def nav_item_map @nav_item_map ||= { 'my-proposals-link' => [ - starts_with_path(Proposal), - starts_with_path(current_event, Proposal) + path_prefix(Proposal), + path_prefix(current_event, Proposal) ], 'event-website-link' => website_subnav_item_map, - 'event-review-proposals-link' => starts_with_path(current_event, :staff, Proposal), + 'event-review-proposals-link' => path_prefix(current_event, :staff, Proposal), 'event-selection-link' => selection_subnav_item_map, 'event-program-link' => program_subnav_item_map, 'event-schedule-link' => schedule_subnav_item_map, @@ -73,13 +73,13 @@ def event_subnav_item_map 'event-staff-teammates-link' => path_for(current_event, :staff, Teammate), 'event-staff-config-link' => path_for(:config, current_event, :staff), 'event-staff-guidelines-link' => path_for(current_event, :staff, :guidelines), - 'event-staff-speaker-emails-link' => starts_with_path(current_event, :staff, :speaker_email_templates), + 'event-staff-speaker-emails-link' => path_prefix(current_event, :staff, :speaker_email_templates), } end def website_subnav_item_map @website_subnav_item_map ||= { - 'event-website-configuration-link' => starts_with_path(current_event, :staff, :website), + 'event-website-configuration-link' => path_prefix(current_event, :staff, :website), 'event-pages-link' => path_for(current_event, :staff, Page) } end @@ -87,19 +87,19 @@ def website_subnav_item_map def selection_subnav_item_map @selection_subnav_item_map ||= { 'event-program-proposals-selection-link' => [ - starts_with_path(:selection, current_event, :staff, :program, Proposal), + path_prefix(:selection, current_event, :staff, :program, Proposal), # add_path(:event_staff_program_proposal, current_event, @proposal) #How to leverage session[:prev_page] here? Considering lamdas ], - 'event-program-bulk-finalize-link' => starts_with_path(:bulk_finalize, current_event, :staff, :program, Proposal), - 'event-program-proposals-link' => starts_with_path(current_event, :staff, :program, Proposal) + 'event-program-bulk-finalize-link' => path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), + 'event-program-proposals-link' => path_prefix(current_event, :staff, :program, Proposal) } end def program_subnav_item_map @program_subnav_item_map ||= { - 'event-program-sessions-link' => starts_with_path(current_event, :staff, ProgramSession), - 'event-program-speakers-link' => starts_with_path(current_event, :staff, :program, Speaker) + 'event-program-sessions-link' => path_prefix(current_event, :staff, ProgramSession), + 'event-program-speakers-link' => path_prefix(current_event, :staff, :program, Speaker) } end @@ -115,7 +115,7 @@ def path_for(*args) url_for(args << {only_path: true}) unless args.include?(nil) # don't generate the path unless all dependencies are present end - def starts_with_path(sym, *deps) + def path_prefix(sym, *deps) starts_with = path_for(sym, *deps) Regexp.new(Regexp.escape(starts_with) + ".*") if starts_with end From 90b8d22f20ca8ea4613b80cf614e78457bce84a6 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 18:39:53 +0900 Subject: [PATCH 05/22] starts_with => prefix feels like it's nothing but this. --- app/controllers/concerns/activate_navigation.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 3904955a0..a4118e2c1 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -115,8 +115,8 @@ def path_for(*args) url_for(args << {only_path: true}) unless args.include?(nil) # don't generate the path unless all dependencies are present end - def path_prefix(sym, *deps) - starts_with = path_for(sym, *deps) - Regexp.new(Regexp.escape(starts_with) + ".*") if starts_with + def path_prefix(*args) + prefix = path_for(*args) + /\A#{Regexp.escape(prefix)}/ if prefix end end From 5d2af8e84ae2e405d4e9e595416c7f910f0af137 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 18:42:34 +0900 Subject: [PATCH 06/22] Indentation << --- .../concerns/activate_navigation.rb | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index a4118e2c1..25b6271a6 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -50,30 +50,30 @@ def match?(paths) def nav_item_map @nav_item_map ||= { - 'my-proposals-link' => [ - path_prefix(Proposal), - path_prefix(current_event, Proposal) - ], - 'event-website-link' => website_subnav_item_map, - 'event-review-proposals-link' => path_prefix(current_event, :staff, Proposal), - 'event-selection-link' => selection_subnav_item_map, - 'event-program-link' => program_subnav_item_map, - 'event-schedule-link' => schedule_subnav_item_map, - 'event-dashboard-link' => event_subnav_item_map, + 'my-proposals-link' => [ + path_prefix(Proposal), + path_prefix(current_event, Proposal) + ], + 'event-website-link' => website_subnav_item_map, + 'event-review-proposals-link' => path_prefix(current_event, :staff, Proposal), + 'event-selection-link' => selection_subnav_item_map, + 'event-program-link' => program_subnav_item_map, + 'event-schedule-link' => schedule_subnav_item_map, + 'event-dashboard-link' => event_subnav_item_map, } end def event_subnav_item_map @event_subnav_item_map ||= { - 'event-staff-dashboard-link' => path_for(current_event, :staff), - 'event-staff-info-link' => [ - path_for(:info, current_event, :staff), - path_for(:edit, current_event, :staff) - ], - 'event-staff-teammates-link' => path_for(current_event, :staff, Teammate), - 'event-staff-config-link' => path_for(:config, current_event, :staff), - 'event-staff-guidelines-link' => path_for(current_event, :staff, :guidelines), - 'event-staff-speaker-emails-link' => path_prefix(current_event, :staff, :speaker_email_templates), + 'event-staff-dashboard-link' => path_for(current_event, :staff), + 'event-staff-info-link' => [ + path_for(:info, current_event, :staff), + path_for(:edit, current_event, :staff) + ], + 'event-staff-teammates-link' => path_for(current_event, :staff, Teammate), + 'event-staff-config-link' => path_for(:config, current_event, :staff), + 'event-staff-guidelines-link' => path_for(current_event, :staff, :guidelines), + 'event-staff-speaker-emails-link' => path_prefix(current_event, :staff, :speaker_email_templates), } end @@ -86,20 +86,18 @@ def website_subnav_item_map def selection_subnav_item_map @selection_subnav_item_map ||= { - 'event-program-proposals-selection-link' => [ - path_prefix(:selection, current_event, :staff, :program, Proposal), - # add_path(:event_staff_program_proposal, current_event, @proposal) - #How to leverage session[:prev_page] here? Considering lamdas - ], - 'event-program-bulk-finalize-link' => path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), - 'event-program-proposals-link' => path_prefix(current_event, :staff, :program, Proposal) + 'event-program-proposals-selection-link' => [ + path_prefix(:selection, current_event, :staff, :program, Proposal), + ], + 'event-program-bulk-finalize-link' => path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), + 'event-program-proposals-link' => path_prefix(current_event, :staff, :program, Proposal) } end def program_subnav_item_map @program_subnav_item_map ||= { - 'event-program-sessions-link' => path_prefix(current_event, :staff, ProgramSession), - 'event-program-speakers-link' => path_prefix(current_event, :staff, :program, Speaker) + 'event-program-sessions-link' => path_prefix(current_event, :staff, ProgramSession), + 'event-program-speakers-link' => path_prefix(current_event, :staff, :program, Speaker) } end From 35f484530db910d169e06da4b2d4c2c0d8690c21 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 19:01:58 +0900 Subject: [PATCH 07/22] Guard properly Currently, if no nav matches, both `@active_nav_key` and `@active_subnav_key` stay nil, and nil || nil is falsy, so we recalculate on every call. --- app/controllers/concerns/activate_navigation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 25b6271a6..3ba22cb80 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -21,7 +21,7 @@ def subnav_item_class(key) private def initialize_nav - return if @active_nav_key || @active_subnav_key + return if defined?(@active_nav_key) @active_nav_key, subnav_map = find_first(nav_item_map) @active_subnav_key, _ = find_first(subnav_map) From b7cb349260f27f2400c76aaf943cc3f64bdbbb93 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 19:04:27 +0900 Subject: [PATCH 08/22] Inline find_first which is just a thin wrapper around Hash#find --- app/controllers/concerns/activate_navigation.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 3ba22cb80..cd4536d8a 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -23,16 +23,8 @@ def subnav_item_class(key) def initialize_nav return if defined?(@active_nav_key) - @active_nav_key, subnav_map = find_first(nav_item_map) - @active_subnav_key, _ = find_first(subnav_map) - end - - def find_first(item_map) - return unless item_map.is_a?(Hash) - - item_map.find do |key, paths| - match?(paths) - end + @active_nav_key, subnav_map = nav_item_map.find { |_, v| match?(v) } + @active_subnav_key, _ = subnav_map.find { |_, v| match?(v) } if subnav_map.is_a?(Hash) end def match?(paths) @@ -44,7 +36,7 @@ def match?(paths) when Array paths.any? { |p| match?(p) } when Hash - find_first(paths).present? + paths.any? { |_, v| match?(v) } end end From da4342ece335035e826bfcdce2913bc145dc21cc Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 19:06:30 +0900 Subject: [PATCH 09/22] =~ => match? --- app/controllers/concerns/activate_navigation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index cd4536d8a..61195b993 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -32,7 +32,7 @@ def match?(paths) when String paths == request.path when Regexp - paths =~ request.path + paths.match?(request.path) when Array paths.any? { |p| match?(p) } when Hash From af06139a1322932137b249da185213f6e4818fab Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 20:41:18 +0900 Subject: [PATCH 10/22] Symbolize nav class keys --- .../concerns/activate_navigation.rb | 54 ++++++++----------- app/views/layouts/_navbar.html.haml | 14 ++--- .../layouts/nav/staff/_event_subnav.html.haml | 12 ++--- .../nav/staff/_program_subnav.html.haml | 4 +- .../nav/staff/_schedule_subnav.html.haml | 6 +-- .../nav/staff/_selection_subnav.html.haml | 6 +-- .../nav/staff/_website_subnav.html.haml | 6 +-- 7 files changed, 47 insertions(+), 55 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 61195b993..a287109de 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -42,62 +42,54 @@ def match?(paths) def nav_item_map @nav_item_map ||= { - 'my-proposals-link' => [ - path_prefix(Proposal), - path_prefix(current_event, Proposal) - ], - 'event-website-link' => website_subnav_item_map, - 'event-review-proposals-link' => path_prefix(current_event, :staff, Proposal), - 'event-selection-link' => selection_subnav_item_map, - 'event-program-link' => program_subnav_item_map, - 'event-schedule-link' => schedule_subnav_item_map, - 'event-dashboard-link' => event_subnav_item_map, + my_proposals: [path_prefix(Proposal), path_prefix(current_event, Proposal)], + event_website: website_subnav_item_map, + event_review_proposals: path_prefix(current_event, :staff, Proposal), + event_selection: selection_subnav_item_map, + event_program: program_subnav_item_map, + event_schedule: schedule_subnav_item_map, + event_dashboard: event_subnav_item_map } end def event_subnav_item_map @event_subnav_item_map ||= { - 'event-staff-dashboard-link' => path_for(current_event, :staff), - 'event-staff-info-link' => [ - path_for(:info, current_event, :staff), - path_for(:edit, current_event, :staff) - ], - 'event-staff-teammates-link' => path_for(current_event, :staff, Teammate), - 'event-staff-config-link' => path_for(:config, current_event, :staff), - 'event-staff-guidelines-link' => path_for(current_event, :staff, :guidelines), - 'event-staff-speaker-emails-link' => path_prefix(current_event, :staff, :speaker_email_templates), + event_staff_dashboard: path_for(current_event, :staff), + event_staff_info: [path_for(:info, current_event, :staff), path_for(:edit, current_event, :staff)], + event_staff_teammates: path_for(current_event, :staff, Teammate), + event_staff_config: path_for(:config, current_event, :staff), + event_staff_guidelines: path_for(current_event, :staff, :guidelines), + event_staff_speaker_emails: path_prefix(current_event, :staff, :speaker_email_templates) } end def website_subnav_item_map @website_subnav_item_map ||= { - 'event-website-configuration-link' => path_prefix(current_event, :staff, :website), - 'event-pages-link' => path_for(current_event, :staff, Page) + event_website_configuration: path_prefix(current_event, :staff, :website), + event_pages: path_for(current_event, :staff, Page) } end def selection_subnav_item_map @selection_subnav_item_map ||= { - 'event-program-proposals-selection-link' => [ - path_prefix(:selection, current_event, :staff, :program, Proposal), - ], - 'event-program-bulk-finalize-link' => path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), - 'event-program-proposals-link' => path_prefix(current_event, :staff, :program, Proposal) + event_program_proposals_selection: path_prefix(:selection, current_event, :staff, :program, Proposal), + event_program_bulk_finalize: path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), + event_program_proposals: path_prefix(current_event, :staff, :program, Proposal) } end def program_subnav_item_map @program_subnav_item_map ||= { - 'event-program-sessions-link' => path_prefix(current_event, :staff, ProgramSession), - 'event-program-speakers-link' => path_prefix(current_event, :staff, :program, Speaker) + event_program_sessions: path_prefix(current_event, :staff, ProgramSession), + event_program_speakers: path_prefix(current_event, :staff, :program, Speaker) } end def schedule_subnav_item_map @schedule_subnav_item_map ||= { - 'event-schedule-time-slots-link' => path_for(current_event, :staff, :schedule, TimeSlot), - 'event-schedule-rooms-link' => path_for(current_event, :staff, :schedule, Room), - 'event-schedule-grid-link' => path_for(current_event, :staff, :schedule, :grid) + event_schedule_time_slots: path_for(current_event, :staff, :schedule, TimeSlot), + event_schedule_rooms: path_for(current_event, :staff, :schedule, Room), + event_schedule_grid: path_for(current_event, :staff, :schedule, :grid) } end diff --git a/app/views/layouts/_navbar.html.haml b/app/views/layouts/_navbar.html.haml index 74d4117f7..1d44ddc05 100644 --- a/app/views/layouts/_navbar.html.haml +++ b/app/views/layouts/_navbar.html.haml @@ -13,35 +13,35 @@ - roles = current_user.teammates.where(event_id: current_event).pluck(:role) - if speaker_nav? - %li.nav-item{class: nav_item_class("my-proposals-link")} + %li.nav-item{class: nav_item_class(:my_proposals)} = link_to proposals_path, class: 'nav-link' do %span My Proposals - if review_nav?(roles) - %li.nav-item{class: nav_item_class("event-review-proposals-link")} + %li.nav-item{class: nav_item_class(:event_review_proposals)} = link_to event_staff_proposals_path(current_event), class: 'nav-link' do %span Review - if program_nav?(roles) - %li.nav-item{class: nav_item_class("event-selection-link")} + %li.nav-item{class: nav_item_class(:event_selection)} = link_to event_staff_program_proposals_path(current_event), class: 'nav-link' do %span Selection - %li.nav-item{class: nav_item_class("event-program-link")} + %li.nav-item{class: nav_item_class(:event_program)} = link_to event_staff_program_sessions_path(current_event), class: 'nav-link' do %span Program - if schedule_nav?(roles) - %li.nav-item{class: nav_item_class("event-schedule-link")} + %li.nav-item{class: nav_item_class(:event_schedule)} = link_to event_staff_schedule_grid_path(current_event), class: 'nav-link' do %span Schedule - if staff_nav?(roles) - %li.nav-item{class: nav_item_class("event-dashboard-link")} + %li.nav-item{class: nav_item_class(:event_dashboard)} = link_to event_staff_path(current_event), class: 'nav-link' do %span Dashboard - if !ENV['DISABLE_WEBSITE'] && website_nav? - %li.nav-item{class: nav_item_class("event-website-link")} + %li.nav-item{class: nav_item_class(:event_website)} = link_to new_or_edit_website_path, class: 'nav-link' do %span Website %sup Beta diff --git a/app/views/layouts/nav/staff/_event_subnav.html.haml b/app/views/layouts/nav/staff/_event_subnav.html.haml index e0e5b7b9c..a9daf82d9 100644 --- a/app/views/layouts/nav/staff/_event_subnav.html.haml +++ b/app/views/layouts/nav/staff/_event_subnav.html.haml @@ -2,27 +2,27 @@ .subnavbar-inner .container-fluid %ul.mainnav - %li{class: subnav_item_class("event-staff-dashboard-link")} + %li{class: subnav_item_class(:event_staff_dashboard)} = link_to event_staff_path do %i.bi.bi-speedometer2 %span Dashboard - %li{class: subnav_item_class("event-staff-info-link")} + %li{class: subnav_item_class(:event_staff_info)} = link_to info_event_staff_path do %i.bi.bi-info-circle %span Info - %li{class: subnav_item_class("event-staff-teammates-link")} + %li{class: subnav_item_class(:event_staff_teammates)} = link_to event_staff_teammates_path do %i.bi.bi-people %span Team - %li{class: subnav_item_class("event-staff-config-link")} + %li{class: subnav_item_class(:event_staff_config)} = link_to config_event_staff_path do %i.bi.bi-wrench %span Config - %li{class: subnav_item_class("event-staff-guidelines-link")} + %li{class: subnav_item_class(:event_staff_guidelines)} = link_to event_staff_guidelines_path do %i.bi.bi-list %span Guidelines - %li{class: subnav_item_class("event-staff-speaker-emails-link")} + %li{class: subnav_item_class(:event_staff_speaker_emails)} = link_to event_staff_speaker_email_templates_path do %i.bi.bi-envelope %span Speaker Emails diff --git a/app/views/layouts/nav/staff/_program_subnav.html.haml b/app/views/layouts/nav/staff/_program_subnav.html.haml index 952bd7fdb..a32067ab1 100644 --- a/app/views/layouts/nav/staff/_program_subnav.html.haml +++ b/app/views/layouts/nav/staff/_program_subnav.html.haml @@ -29,9 +29,9 @@ %span.badge= @all_waitlisted_track_count %ul.navbar-nav.ms-auto - %li.nav-item{class: subnav_item_class("event-program-sessions-link")} + %li.nav-item{class: subnav_item_class(:event_program_sessions)} = link_to event_staff_program_sessions_path, class: 'nav-link' do %span Sessions - %li.nav-item{class: subnav_item_class("event-program-speakers-link")} + %li.nav-item{class: subnav_item_class(:event_program_speakers)} = link_to event_staff_program_speakers_path, class: 'nav-link' do %span Speakers diff --git a/app/views/layouts/nav/staff/_schedule_subnav.html.haml b/app/views/layouts/nav/staff/_schedule_subnav.html.haml index 74b19d156..e7e364e86 100644 --- a/app/views/layouts/nav/staff/_schedule_subnav.html.haml +++ b/app/views/layouts/nav/staff/_schedule_subnav.html.haml @@ -6,15 +6,15 @@ %span.bi.bi-download %span Download Schedule JSON %ul.navbar-nav.ms-auto - %li.nav-item{class: subnav_item_class('event-schedule-grid-link')} + %li.nav-item{class: subnav_item_class(:event_schedule_grid)} = link_to event_staff_schedule_grid_path, class: 'nav-link' do %i.bi.bi-calendar-x %span Grid - %li.nav-item{class: subnav_item_class('event-schedule-time-slots-link')} + %li.nav-item{class: subnav_item_class(:event_schedule_time_slots)} = link_to event_staff_schedule_time_slots_path, class: 'nav-link' do %i.bi.bi-clock %span Time Slots - %li.nav-item{class: subnav_item_class('event-schedule-rooms-link')} + %li.nav-item{class: subnav_item_class(:event_schedule_rooms)} = link_to event_staff_schedule_rooms_path, class: 'nav-link' do %i.bi.bi-tag %span Rooms diff --git a/app/views/layouts/nav/staff/_selection_subnav.html.haml b/app/views/layouts/nav/staff/_selection_subnav.html.haml index 255bf5eea..c807fd859 100644 --- a/app/views/layouts/nav/staff/_selection_subnav.html.haml +++ b/app/views/layouts/nav/staff/_selection_subnav.html.haml @@ -29,12 +29,12 @@ %span.badge= @all_waitlisted_track_count %ul.navbar-nav.ms-auto - %li.nav-item{class: subnav_item_class("event-program-proposals-link")} + %li.nav-item{class: subnav_item_class(:event_program_proposals)} = link_to event_staff_program_proposals_path, class: 'nav-link' do %span Proposals - %li.nav-item{class: subnav_item_class("event-program-proposals-selection-link")} + %li.nav-item{class: subnav_item_class(:event_program_proposals_selection)} = link_to selection_event_staff_program_proposals_path, class: 'nav-link' do %span Selection - %li.nav-item{class: subnav_item_class("event-program-bulk-finalize-link")} + %li.nav-item{class: subnav_item_class(:event_program_bulk_finalize)} = link_to bulk_finalize_event_staff_program_proposals_path, class: 'nav-link' do %span Bulk Finalize diff --git a/app/views/layouts/nav/staff/_website_subnav.html.haml b/app/views/layouts/nav/staff/_website_subnav.html.haml index f57032fd8..09484f6ec 100644 --- a/app/views/layouts/nav/staff/_website_subnav.html.haml +++ b/app/views/layouts/nav/staff/_website_subnav.html.haml @@ -1,12 +1,12 @@ .navbar.navbar-expand-lg.fixed-top.website-subnav .container-fluid %ul.navbar-nav.ms-auto - %li.nav-item{class: subnav_item_class('event-website-configuration-link')} + %li.nav-item{class: subnav_item_class(:event_website_configuration)} = link_to edit_event_staff_website_path(current_event), class: 'nav-link' do %span Configuration - %li.nav-item{class: subnav_item_class('event-pages-link')} + %li.nav-item{class: subnav_item_class(:event_pages)} = link_to event_staff_pages_path(current_event), class: 'nav-link' do %span Pages - %li.nav-item{class: subnav_item_class('event-sponsor-link')} + %li.nav-item{class: subnav_item_class(:event_sponsor)} = link_to event_staff_sponsors_path, class: 'nav-link' do %span Sponsors From 5ccd6239f4c6239dfbca30da748eea7303305d0a Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 21:02:49 +0900 Subject: [PATCH 11/22] Inline *_subnav_item_maps to reduce methods and ivars --- .../concerns/activate_navigation.rb | 72 +++++++------------ 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index a287109de..d431609e3 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -43,53 +43,33 @@ def match?(paths) def nav_item_map @nav_item_map ||= { my_proposals: [path_prefix(Proposal), path_prefix(current_event, Proposal)], - event_website: website_subnav_item_map, + event_website: { + event_website_configuration: path_prefix(current_event, :staff, :website), + event_pages: path_for(current_event, :staff, Page) + }, event_review_proposals: path_prefix(current_event, :staff, Proposal), - event_selection: selection_subnav_item_map, - event_program: program_subnav_item_map, - event_schedule: schedule_subnav_item_map, - event_dashboard: event_subnav_item_map - } - end - - def event_subnav_item_map - @event_subnav_item_map ||= { - event_staff_dashboard: path_for(current_event, :staff), - event_staff_info: [path_for(:info, current_event, :staff), path_for(:edit, current_event, :staff)], - event_staff_teammates: path_for(current_event, :staff, Teammate), - event_staff_config: path_for(:config, current_event, :staff), - event_staff_guidelines: path_for(current_event, :staff, :guidelines), - event_staff_speaker_emails: path_prefix(current_event, :staff, :speaker_email_templates) - } - end - - def website_subnav_item_map - @website_subnav_item_map ||= { - event_website_configuration: path_prefix(current_event, :staff, :website), - event_pages: path_for(current_event, :staff, Page) - } - end - - def selection_subnav_item_map - @selection_subnav_item_map ||= { - event_program_proposals_selection: path_prefix(:selection, current_event, :staff, :program, Proposal), - event_program_bulk_finalize: path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), - event_program_proposals: path_prefix(current_event, :staff, :program, Proposal) - } - end - - def program_subnav_item_map - @program_subnav_item_map ||= { - event_program_sessions: path_prefix(current_event, :staff, ProgramSession), - event_program_speakers: path_prefix(current_event, :staff, :program, Speaker) - } - end - - def schedule_subnav_item_map - @schedule_subnav_item_map ||= { - event_schedule_time_slots: path_for(current_event, :staff, :schedule, TimeSlot), - event_schedule_rooms: path_for(current_event, :staff, :schedule, Room), - event_schedule_grid: path_for(current_event, :staff, :schedule, :grid) + event_selection: { + event_program_proposals_selection: path_prefix(:selection, current_event, :staff, :program, Proposal), + event_program_bulk_finalize: path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), + event_program_proposals: path_prefix(current_event, :staff, :program, Proposal) + }, + event_program: { + event_program_sessions: path_prefix(current_event, :staff, ProgramSession), + event_program_speakers: path_prefix(current_event, :staff, :program, Speaker) + }, + event_schedule: { + event_schedule_time_slots: path_for(current_event, :staff, :schedule, TimeSlot), + event_schedule_rooms: path_for(current_event, :staff, :schedule, Room), + event_schedule_grid: path_for(current_event, :staff, :schedule, :grid) + }, + event_dashboard: { + event_staff_dashboard: path_for(current_event, :staff), + event_staff_info: [path_for(:info, current_event, :staff), path_for(:edit, current_event, :staff)], + event_staff_teammates: path_for(current_event, :staff, Teammate), + event_staff_config: path_for(:config, current_event, :staff), + event_staff_guidelines: path_for(current_event, :staff, :guidelines), + event_staff_speaker_emails: path_prefix(current_event, :staff, :speaker_email_templates) + } } end From 0bbe2eb6cfae65615da0637cc2f2df90821f9a15 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 22:59:53 +0900 Subject: [PATCH 12/22] Store navigation paths with Proc so the given request.path can dynamically match using current_event. This eliminates creation of Regexp objects, and reduces execution of url_for helpers. --- .../concerns/activate_navigation.rb | 49 ++++++++----------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index d431609e3..d90bd0ed6 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -29,10 +29,8 @@ def initialize_nav def match?(paths) case paths - when String - paths == request.path - when Regexp - paths.match?(request.path) + when Proc + paths.call(request.path) when Array paths.any? { |p| match?(p) } when Hash @@ -42,43 +40,38 @@ def match?(paths) def nav_item_map @nav_item_map ||= { - my_proposals: [path_prefix(Proposal), path_prefix(current_event, Proposal)], + my_proposals: [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }], event_website: { - event_website_configuration: path_prefix(current_event, :staff, :website), - event_pages: path_for(current_event, :staff, Page) + event_website_configuration: ->(p) { p.start_with?(path_for(current_event, :staff, :website)) }, + event_pages: ->(p) { p == path_for(current_event, :staff, Page) } }, - event_review_proposals: path_prefix(current_event, :staff, Proposal), + event_review_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, Proposal)) }, event_selection: { - event_program_proposals_selection: path_prefix(:selection, current_event, :staff, :program, Proposal), - event_program_bulk_finalize: path_prefix(:bulk_finalize, current_event, :staff, :program, Proposal), - event_program_proposals: path_prefix(current_event, :staff, :program, Proposal) + event_program_proposals_selection: ->(p) { p.start_with?(path_for(:selection, current_event, :staff, :program, Proposal)) }, + event_program_bulk_finalize: ->(p) { p.start_with?(path_for(:bulk_finalize, current_event, :staff, :program, Proposal)) }, + event_program_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, :program, Proposal)) } }, event_program: { - event_program_sessions: path_prefix(current_event, :staff, ProgramSession), - event_program_speakers: path_prefix(current_event, :staff, :program, Speaker) + event_program_sessions: ->(p) { p.start_with?(path_for(current_event, :staff, ProgramSession)) }, + event_program_speakers: ->(p) { p.start_with?(path_for(current_event, :staff, :program, Speaker)) } }, event_schedule: { - event_schedule_time_slots: path_for(current_event, :staff, :schedule, TimeSlot), - event_schedule_rooms: path_for(current_event, :staff, :schedule, Room), - event_schedule_grid: path_for(current_event, :staff, :schedule, :grid) + event_schedule_time_slots: ->(p) { p == path_for(current_event, :staff, :schedule, TimeSlot) }, + event_schedule_rooms: ->(p) { p == path_for(current_event, :staff, :schedule, Room) }, + event_schedule_grid: ->(p) { p == path_for(current_event, :staff, :schedule, :grid) } }, event_dashboard: { - event_staff_dashboard: path_for(current_event, :staff), - event_staff_info: [path_for(:info, current_event, :staff), path_for(:edit, current_event, :staff)], - event_staff_teammates: path_for(current_event, :staff, Teammate), - event_staff_config: path_for(:config, current_event, :staff), - event_staff_guidelines: path_for(current_event, :staff, :guidelines), - event_staff_speaker_emails: path_prefix(current_event, :staff, :speaker_email_templates) + event_staff_dashboard: ->(p) { p == path_for(current_event, :staff) }, + event_staff_info: [->(p) { p == path_for(:info, current_event, :staff) }, ->(p) { p == path_for(:edit, current_event, :staff) }], + event_staff_teammates: ->(p) { p == path_for(current_event, :staff, Teammate) }, + event_staff_config: ->(p) { p == path_for(:config, current_event, :staff) }, + event_staff_guidelines: ->(p) { p == path_for(current_event, :staff, :guidelines) }, + event_staff_speaker_emails: ->(p) { p.start_with?(path_for(current_event, :staff, :speaker_email_templates)) } } } end def path_for(*args) - url_for(args << {only_path: true}) unless args.include?(nil) # don't generate the path unless all dependencies are present - end - - def path_prefix(*args) - prefix = path_for(*args) - /\A#{Regexp.escape(prefix)}/ if prefix + url_for(args << {only_path: true}) end end From dc368b68f35d523d8c1a88d38b2c5f897ef95296 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 23:11:58 +0900 Subject: [PATCH 13/22] Constantize nav_item_map since all path helpers are dynamically executed now, we can share this whole navigation map globally across all requests now. --- .../concerns/activate_navigation.rb | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index d90bd0ed6..2a8c606e6 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -1,6 +1,37 @@ require "active_support/concern" module ActivateNavigation + NAV_ITEM_MAP = { + my_proposals: [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }], + event_website: { + event_website_configuration: ->(p) { p.start_with?(path_for(current_event, :staff, :website)) }, + event_pages: ->(p) { p == path_for(current_event, :staff, Page) } + }, + event_review_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, Proposal)) }, + event_selection: { + event_program_proposals_selection: ->(p) { p.start_with?(path_for(:selection, current_event, :staff, :program, Proposal)) }, + event_program_bulk_finalize: ->(p) { p.start_with?(path_for(:bulk_finalize, current_event, :staff, :program, Proposal)) }, + event_program_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, :program, Proposal)) } + }, + event_program: { + event_program_sessions: ->(p) { p.start_with?(path_for(current_event, :staff, ProgramSession)) }, + event_program_speakers: ->(p) { p.start_with?(path_for(current_event, :staff, :program, Speaker)) } + }, + event_schedule: { + event_schedule_time_slots: ->(p) { p == path_for(current_event, :staff, :schedule, TimeSlot) }, + event_schedule_rooms: ->(p) { p == path_for(current_event, :staff, :schedule, Room) }, + event_schedule_grid: ->(p) { p == path_for(current_event, :staff, :schedule, :grid) } + }, + event_dashboard: { + event_staff_dashboard: ->(p) { p == path_for(current_event, :staff) }, + event_staff_info: [->(p) { p == path_for(:info, current_event, :staff) }, ->(p) { p == path_for(:edit, current_event, :staff) }], + event_staff_teammates: ->(p) { p == path_for(current_event, :staff, Teammate) }, + event_staff_config: ->(p) { p == path_for(:config, current_event, :staff) }, + event_staff_guidelines: ->(p) { p == path_for(current_event, :staff, :guidelines) }, + event_staff_speaker_emails: ->(p) { p.start_with?(path_for(current_event, :staff, :speaker_email_templates)) } + } + }.freeze + extend ActiveSupport::Concern included do @@ -23,14 +54,14 @@ def subnav_item_class(key) def initialize_nav return if defined?(@active_nav_key) - @active_nav_key, subnav_map = nav_item_map.find { |_, v| match?(v) } + @active_nav_key, subnav_map = NAV_ITEM_MAP.find { |_, v| match?(v) } @active_subnav_key, _ = subnav_map.find { |_, v| match?(v) } if subnav_map.is_a?(Hash) end def match?(paths) case paths when Proc - paths.call(request.path) + instance_exec(request.path, &paths) when Array paths.any? { |p| match?(p) } when Hash @@ -38,39 +69,6 @@ def match?(paths) end end - def nav_item_map - @nav_item_map ||= { - my_proposals: [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }], - event_website: { - event_website_configuration: ->(p) { p.start_with?(path_for(current_event, :staff, :website)) }, - event_pages: ->(p) { p == path_for(current_event, :staff, Page) } - }, - event_review_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, Proposal)) }, - event_selection: { - event_program_proposals_selection: ->(p) { p.start_with?(path_for(:selection, current_event, :staff, :program, Proposal)) }, - event_program_bulk_finalize: ->(p) { p.start_with?(path_for(:bulk_finalize, current_event, :staff, :program, Proposal)) }, - event_program_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, :program, Proposal)) } - }, - event_program: { - event_program_sessions: ->(p) { p.start_with?(path_for(current_event, :staff, ProgramSession)) }, - event_program_speakers: ->(p) { p.start_with?(path_for(current_event, :staff, :program, Speaker)) } - }, - event_schedule: { - event_schedule_time_slots: ->(p) { p == path_for(current_event, :staff, :schedule, TimeSlot) }, - event_schedule_rooms: ->(p) { p == path_for(current_event, :staff, :schedule, Room) }, - event_schedule_grid: ->(p) { p == path_for(current_event, :staff, :schedule, :grid) } - }, - event_dashboard: { - event_staff_dashboard: ->(p) { p == path_for(current_event, :staff) }, - event_staff_info: [->(p) { p == path_for(:info, current_event, :staff) }, ->(p) { p == path_for(:edit, current_event, :staff) }], - event_staff_teammates: ->(p) { p == path_for(current_event, :staff, Teammate) }, - event_staff_config: ->(p) { p == path_for(:config, current_event, :staff) }, - event_staff_guidelines: ->(p) { p == path_for(current_event, :staff, :guidelines) }, - event_staff_speaker_emails: ->(p) { p.start_with?(path_for(current_event, :staff, :speaker_email_templates)) } - } - } - end - def path_for(*args) url_for(args << {only_path: true}) end From 16d40544ebacedf99874987a794d9cf6d518e35f Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 23:23:45 +0900 Subject: [PATCH 14/22] All subnav items are Proc now --- app/controllers/concerns/activate_navigation.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 2a8c606e6..99012bdb3 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -24,7 +24,7 @@ module ActivateNavigation }, event_dashboard: { event_staff_dashboard: ->(p) { p == path_for(current_event, :staff) }, - event_staff_info: [->(p) { p == path_for(:info, current_event, :staff) }, ->(p) { p == path_for(:edit, current_event, :staff) }], + event_staff_info: ->(pp) { [->(p) { p == path_for(:info, current_event, :staff) }, ->(p) { p == path_for(:edit, current_event, :staff) }].any? { it.call(pp) } }, event_staff_teammates: ->(p) { p == path_for(current_event, :staff, Teammate) }, event_staff_config: ->(p) { p == path_for(:config, current_event, :staff) }, event_staff_guidelines: ->(p) { p == path_for(current_event, :staff, :guidelines) }, @@ -55,7 +55,7 @@ def initialize_nav return if defined?(@active_nav_key) @active_nav_key, subnav_map = NAV_ITEM_MAP.find { |_, v| match?(v) } - @active_subnav_key, _ = subnav_map.find { |_, v| match?(v) } if subnav_map.is_a?(Hash) + @active_subnav_key, _ = subnav_map.find { |_, v| instance_exec(request.path, &v) } if subnav_map.is_a?(Hash) end def match?(paths) From 0943c167bb03b68efb5419acf0e26172b3b315b9 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 23:33:38 +0900 Subject: [PATCH 15/22] All nav items are also non-Array now so we can eliminate the Array case --- app/controllers/concerns/activate_navigation.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 99012bdb3..fd751e1c5 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -2,7 +2,7 @@ module ActivateNavigation NAV_ITEM_MAP = { - my_proposals: [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }], + my_proposals: ->(pp) { [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }].any? { it.call(pp) } }, event_website: { event_website_configuration: ->(p) { p.start_with?(path_for(current_event, :staff, :website)) }, event_pages: ->(p) { p == path_for(current_event, :staff, Page) } @@ -62,8 +62,6 @@ def match?(paths) case paths when Proc instance_exec(request.path, &paths) - when Array - paths.any? { |p| match?(p) } when Hash paths.any? { |_, v| match?(v) } end From 3aacf506615b5effa9801f15634e8befcfeaa067 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 26 Dec 2025 23:55:17 +0900 Subject: [PATCH 16/22] Traverse NAV_ITEM_MAP once where it used to be done twice. Also, we could finally eliminate a method that was defined for all controllers with too general name "match?". --- .../concerns/activate_navigation.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index fd751e1c5..498b269ef 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -54,16 +54,15 @@ def subnav_item_class(key) def initialize_nav return if defined?(@active_nav_key) - @active_nav_key, subnav_map = NAV_ITEM_MAP.find { |_, v| match?(v) } - @active_subnav_key, _ = subnav_map.find { |_, v| instance_exec(request.path, &v) } if subnav_map.is_a?(Hash) - end - - def match?(paths) - case paths - when Proc - instance_exec(request.path, &paths) - when Hash - paths.any? { |_, v| match?(v) } + NAV_ITEM_MAP.find do |nav_key, nav_val| + case nav_val + when Proc + @active_nav_key = nav_key if instance_exec(request.path, &nav_val) + when Hash + nav_val.find do |subnav_key, subnav_val| + @active_nav_key, @active_subnav_key = nav_key, subnav_key if instance_exec(request.path, &subnav_val) + end + end end end From bc5bfb107bde8860c6f157427a29ffcfc0320d12 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Sat, 27 Dec 2025 00:04:50 +0900 Subject: [PATCH 17/22] Inline initialize_nav in nav_item_class with an assumption that subnav_item_class is always called AFTER nav_item_class was called at least once. --- .../concerns/activate_navigation.rb | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 498b269ef..492aa2b90 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -40,32 +40,28 @@ module ActivateNavigation end def nav_item_class(key) - initialize_nav + unless defined?(@active_nav_key) + NAV_ITEM_MAP.find do |nav_key, nav_val| + case nav_val + when Proc + @active_nav_key = nav_key if instance_exec(request.path, &nav_val) + when Hash + nav_val.find do |subnav_key, subnav_val| + @active_nav_key, @active_subnav_key = nav_key, subnav_key if instance_exec(request.path, &subnav_val) + end + end + end + end + return 'active' if @active_nav_key == key end def subnav_item_class(key) - initialize_nav return 'active' if @active_subnav_key == key end private - def initialize_nav - return if defined?(@active_nav_key) - - NAV_ITEM_MAP.find do |nav_key, nav_val| - case nav_val - when Proc - @active_nav_key = nav_key if instance_exec(request.path, &nav_val) - when Hash - nav_val.find do |subnav_key, subnav_val| - @active_nav_key, @active_subnav_key = nav_key, subnav_key if instance_exec(request.path, &subnav_val) - end - end - end - end - def path_for(*args) url_for(args << {only_path: true}) end From 4492888e8af51768bc41deb5098746421cd978f7 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Sat, 27 Dec 2025 00:07:04 +0900 Subject: [PATCH 18/22] No returning --- app/controllers/concerns/activate_navigation.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/activate_navigation.rb b/app/controllers/concerns/activate_navigation.rb index 492aa2b90..7dd1e0601 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/controllers/concerns/activate_navigation.rb @@ -53,11 +53,11 @@ def nav_item_class(key) end end - return 'active' if @active_nav_key == key + 'active' if @active_nav_key == key end def subnav_item_class(key) - return 'active' if @active_subnav_key == key + 'active' if @active_subnav_key == key end private From 63eb19bdd403eb04b3dd1feed6df7c94e5383bbb Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Sat, 27 Dec 2025 00:10:12 +0900 Subject: [PATCH 19/22] Navbar helpers are indeed purely helper methods No need to define them in controllers, because we call them only from view files. --- app/controllers/application_controller.rb | 1 - .../navbar_helper.rb} | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) rename app/{controllers/concerns/activate_navigation.rb => helpers/navbar_helper.rb} (93%) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ace1d8c97..f1cc7dcac 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,5 @@ class ApplicationController < ActionController::Base include Pundit::Authorization - include ActivateNavigation rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized # Prevent CSRF attacks by raising an exception. diff --git a/app/controllers/concerns/activate_navigation.rb b/app/helpers/navbar_helper.rb similarity index 93% rename from app/controllers/concerns/activate_navigation.rb rename to app/helpers/navbar_helper.rb index 7dd1e0601..12bbbc01c 100644 --- a/app/controllers/concerns/activate_navigation.rb +++ b/app/helpers/navbar_helper.rb @@ -1,6 +1,4 @@ -require "active_support/concern" - -module ActivateNavigation +module NavbarHelper NAV_ITEM_MAP = { my_proposals: ->(pp) { [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }].any? { it.call(pp) } }, event_website: { @@ -32,13 +30,6 @@ module ActivateNavigation } }.freeze - extend ActiveSupport::Concern - - included do - helper_method :nav_item_class - helper_method :subnav_item_class - end - def nav_item_class(key) unless defined?(@active_nav_key) NAV_ITEM_MAP.find do |nav_key, nav_val| From f6d895d2f9072293d5718dbc0f4a63bdd6f8eaa9 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Sat, 27 Dec 2025 00:15:28 +0900 Subject: [PATCH 20/22] Helper methods could be private --- app/helpers/navbar_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/navbar_helper.rb b/app/helpers/navbar_helper.rb index 12bbbc01c..6a7023968 100644 --- a/app/helpers/navbar_helper.rb +++ b/app/helpers/navbar_helper.rb @@ -30,6 +30,8 @@ module NavbarHelper } }.freeze + private + def nav_item_class(key) unless defined?(@active_nav_key) NAV_ITEM_MAP.find do |nav_key, nav_val| @@ -51,8 +53,6 @@ def subnav_item_class(key) 'active' if @active_subnav_key == key end - private - def path_for(*args) url_for(args << {only_path: true}) end From 4876836db20c18cd0ccc9a2ee28b158ea2b93876 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Sat, 27 Dec 2025 00:37:11 +0900 Subject: [PATCH 21/22] Order navs and subnavs by actually displayed order for intuitiveness. --- app/helpers/navbar_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/helpers/navbar_helper.rb b/app/helpers/navbar_helper.rb index 6a7023968..12547abb7 100644 --- a/app/helpers/navbar_helper.rb +++ b/app/helpers/navbar_helper.rb @@ -1,10 +1,6 @@ module NavbarHelper NAV_ITEM_MAP = { my_proposals: ->(pp) { [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }].any? { it.call(pp) } }, - event_website: { - event_website_configuration: ->(p) { p.start_with?(path_for(current_event, :staff, :website)) }, - event_pages: ->(p) { p == path_for(current_event, :staff, Page) } - }, event_review_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, Proposal)) }, event_selection: { event_program_proposals_selection: ->(p) { p.start_with?(path_for(:selection, current_event, :staff, :program, Proposal)) }, @@ -27,6 +23,10 @@ module NavbarHelper event_staff_config: ->(p) { p == path_for(:config, current_event, :staff) }, event_staff_guidelines: ->(p) { p == path_for(current_event, :staff, :guidelines) }, event_staff_speaker_emails: ->(p) { p.start_with?(path_for(current_event, :staff, :speaker_email_templates)) } + }, + event_website: { + event_website_configuration: ->(p) { p.start_with?(path_for(current_event, :staff, :website)) }, + event_pages: ->(p) { p == path_for(current_event, :staff, Page) } } }.freeze From bf04d10fd19d4f71d9670246cd7f73d001df5d8d Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Sat, 27 Dec 2025 00:22:55 +0900 Subject: [PATCH 22/22] Define path_for as a NavbarHelper super-private method because we don't use this anywhere else. --- app/helpers/navbar_helper.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/helpers/navbar_helper.rb b/app/helpers/navbar_helper.rb index 12547abb7..07265d5c6 100644 --- a/app/helpers/navbar_helper.rb +++ b/app/helpers/navbar_helper.rb @@ -1,4 +1,12 @@ module NavbarHelper + using Module.new { + refine NavbarHelper do + def path_for(*args) + url_for(args << {only_path: true}) + end + end + } + NAV_ITEM_MAP = { my_proposals: ->(pp) { [->(p) { p.start_with?(path_for(Proposal)) }, ->(p) { p.start_with?(path_for(current_event, Proposal)) }].any? { it.call(pp) } }, event_review_proposals: ->(p) { p.start_with?(path_for(current_event, :staff, Proposal)) }, @@ -52,8 +60,4 @@ def nav_item_class(key) def subnav_item_class(key) 'active' if @active_subnav_key == key end - - def path_for(*args) - url_for(args << {only_path: true}) - end end