@@ -201,6 +201,7 @@ def initialize(source, identifier, handler, locals:, format: nil, variant: nil,
201
201
@variant = variant
202
202
@compile_mutex = Mutex . new
203
203
@strict_locals = NONE
204
+ @strict_local_keys = nil
204
205
@type = nil
205
206
end
206
207
@@ -244,9 +245,15 @@ def supports_streaming?
244
245
# This method is instrumented as "!render_template.action_view". Notice that
245
246
# we use a bang in this instrumentation because you don't want to
246
247
# consume this in production. This is only slow if it's being listened to.
247
- def render ( view , locals , buffer = nil , add_to_stack : true , &block )
248
+ def render ( view , locals , buffer = nil , implicit_locals : [ ] , add_to_stack : true , &block )
248
249
instrument_render_template do
249
250
compile! ( view )
251
+
252
+ if strict_locals? && @strict_local_keys && !implicit_locals . empty?
253
+ locals_to_ignore = implicit_locals - @strict_local_keys
254
+ locals . except! ( *locals_to_ignore )
255
+ end
256
+
250
257
if buffer
251
258
view . _run ( method_name , self , locals , buffer , add_to_stack : add_to_stack , has_strict_locals : strict_locals? , &block )
252
259
nil
@@ -474,23 +481,30 @@ def compile(mod)
474
481
475
482
return unless strict_locals?
476
483
484
+ parameters = mod . instance_method ( method_name ) . parameters - [ [ :req , :output_buffer ] ]
477
485
# Check compiled method parameters to ensure that only kwargs
478
486
# were provided as strict locals, preventing `locals: (foo, *foo)` etc
479
487
# and allowing `locals: (foo:)`.
480
488
481
- non_kwarg_parameters =
482
- ( mod . instance_method ( method_name ) . parameters - [ [ :req , :output_buffer ] ] ) .
483
- select { | parameter | ! [ :keyreq , :key , :keyrest , :nokey ] . include? ( parameter [ 0 ] ) }
489
+ non_kwarg_parameters = parameters . select do | parameter |
490
+ ! [ :keyreq , :key , :keyrest , :nokey ] . include? ( parameter [ 0 ] )
491
+ end
484
492
485
- return unless non_kwarg_parameters . any?
493
+ unless non_kwarg_parameters . empty?
494
+ mod . undef_method ( method_name )
486
495
487
- mod . undef_method ( method_name )
496
+ raise ArgumentError . new (
497
+ "#{ non_kwarg_parameters . map { |_ , name | "`#{ name } `" } . to_sentence } set as non-keyword " \
498
+ "#{ 'argument' . pluralize ( non_kwarg_parameters . length ) } for #{ short_identifier } . " \
499
+ "Locals can only be set as keyword arguments."
500
+ )
501
+ end
488
502
489
- raise ArgumentError . new (
490
- " #{ non_kwarg_parameters . map { | _ , name | "` #{ name } `" } . to_sentence } set as non-keyword " \
491
- " #{ 'argument' . pluralize ( non_kwarg_parameters . length ) } for #{ short_identifier } . " \
492
- "Locals can only be set as keyword arguments."
493
- )
503
+ unless parameters . any? { | type , _ | type == :keyrest }
504
+ parameters . map! ( & :first )
505
+ parameters . sort!
506
+ @strict_local_keys = parameters . freeze
507
+ end
494
508
end
495
509
496
510
def offset
0 commit comments