@@ -72,20 +72,133 @@ def merge_rails_filter_parameters!
7272
7373 rails_filter_params = ::Rails . application . config . filter_parameters
7474 return unless rails_filter_params . is_a? ( Array )
75+ return if rails_filter_params . empty?
76+
77+ symbol_filters = T . let ( [ ] , T ::Array [ Symbol ] )
78+ matchers = T . let ( [ ] , T ::Array [ ConfigStruct ::FilterMatcher ] )
79+ leftovers = T . let ( [ ] , T ::Array [ T . untyped ] )
80+
81+ rails_filter_params . each do |entry |
82+ matcher = build_filter_matcher ( entry )
83+
84+ if matcher
85+ matchers << matcher
86+ next
87+ end
88+
89+ normalized_symbol = normalize_filter_symbol ( entry )
90+ if normalized_symbol
91+ symbol_filters << normalized_symbol
92+ else
93+ leftovers << entry
94+ end
95+ end
96+
97+ if symbol_filters . any?
98+ config . filters . filter_keys |= symbol_filters
99+ end
75100
76- # Convert all Rails filter parameters to symbols and merge with our filter keys
77- converted_params = rails_filter_params . map do |param |
78- param . respond_to? ( :to_sym ) ? param . to_sym : param
101+ if matchers . any?
102+ matchers . each do |matcher |
103+ existing = config . filters . filter_matchers . any? do |registered |
104+ registered . label == matcher . label
105+ end
106+ config . filters . filter_matchers << matcher unless existing
107+ end
79108 end
80109
81- # Add Rails filter parameters to our filter keys
82- config . filters . filter_keys += converted_params
110+ replace_filter_parameters ( rails_filter_params , leftovers )
111+ end
112+
113+ private
114+
115+ sig { params ( filter : T . untyped ) . returns ( T . nilable ( Symbol ) ) }
116+ def normalize_filter_symbol ( filter )
117+ return filter if filter . is_a? ( Symbol )
118+ return filter . downcase . to_sym if filter . is_a? ( String )
83119
84- # Ensure no duplicates
85- config . filters . filter_keys . uniq!
120+ return nil unless filter . respond_to? ( :to_sym )
121+
122+ begin
123+ sym = filter . to_sym
124+ sym . is_a? ( Symbol ) ? sym : nil
125+ rescue
126+ nil
127+ end
128+ end
129+
130+ sig { params ( filter : T . untyped ) . returns ( T . nilable ( ConfigStruct ::FilterMatcher ) ) }
131+ def build_filter_matcher ( filter )
132+ case filter
133+ when ::Regexp
134+ callable = Kernel . lambda do |key , _value |
135+ filter . match? ( key )
136+ end
137+ return ConfigStruct ::FilterMatcher . new ( callable : callable , label : filter . inspect )
138+ else
139+ return build_callable_filter_matcher ( filter ) if callable_filter? ( filter )
140+ end
141+
142+ nil
143+ end
144+
145+ sig { params ( filter : T . untyped ) . returns ( T ::Boolean ) }
146+ def callable_filter? ( filter )
147+ filter . respond_to? ( :call )
148+ end
149+
150+ sig { params ( filter : T . untyped ) . returns ( T . nilable ( ConfigStruct ::FilterMatcher ) ) }
151+ def build_callable_filter_matcher ( filter )
152+ callable = Kernel . lambda do |key , value |
153+ call_args = case arity_for_filter ( filter )
154+ when 0
155+ [ ]
156+ when 1
157+ [ key ]
158+ else
159+ [ key , value ]
160+ end
161+
162+ result = filter . call ( *call_args )
163+ !!result
164+ rescue ArgumentError
165+ begin
166+ !!filter . call ( key )
167+ rescue => e
168+ handle_filter_error ( e , filter , key )
169+ false
170+ end
171+ rescue => e
172+ handle_filter_error ( e , filter , key )
173+ false
174+ end
175+ ConfigStruct ::FilterMatcher . new ( callable : callable , label : filter . inspect )
176+ end
177+
178+ sig { params ( filter : T . untyped ) . returns ( Integer ) }
179+ def arity_for_filter ( filter )
180+ filter . respond_to? ( :arity ) ? filter . arity : 2
181+ end
182+
183+ sig { params ( filter_params : T ::Array [ T . untyped ] , leftovers : T ::Array [ T . untyped ] ) . void }
184+ def replace_filter_parameters ( filter_params , leftovers )
185+ filter_params . clear
186+ filter_params . concat ( leftovers )
187+ end
86188
87- # Clear Rails filter parameters since we've incorporated them
88- ::Rails . application . config . filter_parameters . clear
189+ sig { params ( error : StandardError , filter : T . untyped , key : String ) . void }
190+ def handle_filter_error ( error , filter , key )
191+ context = {
192+ filter : filter . class . name ,
193+ key : key ,
194+ filter_label : begin
195+ filter . inspect
196+ rescue
197+ "unknown"
198+ end
199+ }
200+
201+ LogStruct . handle_exception ( error , source : Source ::Internal , context : context )
89202 end
90203 end
91204 end
0 commit comments