40 lines
2 KiB
Diff
40 lines
2 KiB
Diff
# UNDF: UNDF-2026-000000251
|
||
Fixes rails-0012: options_for_select — Array(selected).include? and Array(disabled).include? inside container.map loop O(N×S) per select render.
|
||
|
||
--- a/actionview/lib/action_view/helpers/form_options_helper.rb
|
||
+++ b/actionview/lib/action_view/helpers/form_options_helper.rb
|
||
|
||
@@ DEFECT rails-0012: lines 357-374
|
||
|
||
def options_for_select(container, selected = nil)
|
||
return container if String === container
|
||
|
||
selected, disabled = extract_selected_and_disabled(selected).map do |r|
|
||
- Array(r).map(&:to_s) # O(S), O(D) — still Arrays
|
||
+ Array(r).map(&:to_s).to_set # FIX: O(1) include? below
|
||
end
|
||
|
||
container.map do |element|
|
||
html_attributes = option_html_attributes(element)
|
||
text, value = option_text_and_value(element).map(&:to_s)
|
||
|
||
- html_attributes[:selected] ||= option_value_selected?(value, selected) # O(S) per option
|
||
- html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled) # O(D) per option
|
||
+ html_attributes[:selected] ||= option_value_selected?(value, selected)
|
||
+ html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled)
|
||
html_attributes[:value] = value
|
||
|
||
tag_builder.option(text, **html_attributes)
|
||
end.join("\n").html_safe
|
||
end
|
||
|
||
# NOTE: option_value_selected? already calls Array(selected).include? — the fix is
|
||
# to ensure selected/disabled are Sets before the loop so include? is O(1).
|
||
|
||
# BEFORE: selected/disabled are Arrays; include? is O(S) or O(D) per option element
|
||
# container has N options: total O(N×S + N×D) per render
|
||
# AFTER: selected/disabled converted to Set before loop: O(1) include? per option
|
||
# total O(N) per render
|
||
# Severity: HIGH — every select tag with a pre-selected value hits this path
|
||
# Speedup: ~S× where S = number of selected values (multi-select: up to 100+)
|
||
# At N=500 options, S=50 selected: 25,000 comparisons → 500
|