51 lines
2.2 KiB
Diff
51 lines
2.2 KiB
Diff
# UNDF: UNDF-2026-000000252
|
||
Fixes rails-0013: CollectionHelpers#default_html_options_for_collection — Array(current_value).map(&:to_s).include? inside render_collection loop O(C×V×4) per collection render.
|
||
|
||
--- a/actionview/lib/action_view/helpers/tags/collection_helpers.rb
|
||
+++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb
|
||
|
||
@@ DEFECT rails-0013: lines 47-69 and 75-84
|
||
|
||
def default_html_options_for_collection(item, value)
|
||
html_options = @html_options.dup
|
||
|
||
[:checked, :selected, :disabled, :readonly].each do |option|
|
||
current_value = @options[option]
|
||
next if current_value.nil?
|
||
|
||
accept = if current_value.respond_to?(:call)
|
||
current_value.call(item)
|
||
else
|
||
- Array(current_value).map(&:to_s).include?(value.to_s) # O(V) Array rebuild + scan per item
|
||
+ # moved to render_collection: @_option_sets[option] is a pre-built Set
|
||
+ @_option_sets[option].include?(value.to_s) # FIX: O(1) per item
|
||
end
|
||
...
|
||
end
|
||
end
|
||
|
||
+ def build_option_sets
|
||
+ @_option_sets = {}
|
||
+ [:checked, :selected, :disabled, :readonly].each do |opt|
|
||
+ val = @options[opt]
|
||
+ next if val.nil? || val.respond_to?(:call)
|
||
+ @_option_sets[opt] = Array(val).map(&:to_s).to_set # FIX: build once O(V)
|
||
+ end
|
||
+ end
|
||
|
||
def render_collection
|
||
+ build_option_sets
|
||
@collection.map do |item|
|
||
value = value_for_collection(item, @value_method)
|
||
...
|
||
end
|
||
end
|
||
|
||
# BEFORE: Array(current_value).map(&:to_s).include?(value.to_s) — rebuilds the array
|
||
# AND scans it for every item × every option type
|
||
# C items × 4 option types × V values = O(C×4×V) per render
|
||
# AFTER: Sets built once before the loop; O(1) lookup per item × option type
|
||
# O(C×4) per render
|
||
# Severity: HIGH — every collection_check_boxes / collection_radio_buttons hits this path
|
||
# Speedup: ~V× where V = number of option values (typical: 2-50)
|
||
# At C=200 items, V=20 checked values: 16,000 → 800 ops per render
|