view_component 3.25.0 → 3.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17958e9ab2fbfbce6d2d397332fb0683315d805bb2ca94920a570fcf544c43e8
4
- data.tar.gz: 76b1b5f122715ac0086e78b8010dc5f03e9fad57180ce444c68f556b148d1a59
3
+ metadata.gz: ea3b7eaa6244e04ffa83e7c9d4aeafca18230bedcce0fb160b1001b0441270b0
4
+ data.tar.gz: aa605998a6e975f74c307faca61ec6d10b837cdee83c48fe2424e5b6421daf8a
5
5
  SHA512:
6
- metadata.gz: 1ef7030f4690849614463924c9f10953609ef1a74508718cbe5d5f5049256ffcc51c67671a1b95a770bd96c0cd0b3b1f0f438bf56c3ba2265b252d1072f3faad
7
- data.tar.gz: b54825e954ceef4e0f45bbc71cc59f92689275f02da9707e46c3fb30b30eb280b9e01b0b3585b3e6996da92dd5ce2c822d9dd839373e8a89660203a665a0ebb3
6
+ metadata.gz: a3ec820b42851cb62062972e1473ebb508798e0acd63bfff6e6fda1087c62776806c0199a9e11d6b13bd2914330bf0ad1cb899511c55f62af1538be7a9292a13
7
+ data.tar.gz: 748b43b70dec2efc5319bec3379f6b7cf115789f731e3a32af789c304644d20f14d62c9bc727ab88baa4a52dbeba806f8f403dcee1bcf1bc9a6df6ee73f0d412
@@ -23,7 +23,7 @@ module PreviewHelper
23
23
  end
24
24
 
25
25
  def find_template_data_for_preview_source(lookup_context:, template_identifier:)
26
- template = lookup_context.find_template(template_identifier)
26
+ template = find_template_for_preview_source(lookup_context, template_identifier)
27
27
 
28
28
  if Rails.version.to_f >= 6.1 || template.source.present?
29
29
  {
@@ -61,6 +61,14 @@ module PreviewHelper
61
61
 
62
62
  private
63
63
 
64
+ def find_template_for_preview_source(lookup_context, template_identifier)
65
+ if lookup_context.respond_to?(:find_template)
66
+ lookup_context.find_template(template_identifier)
67
+ else
68
+ lookup_context.find(template_identifier)
69
+ end
70
+ end
71
+
64
72
  def prism_language_name_by_template(template:)
65
73
  language = template.identifier.split(".").last
66
74
 
data/docs/CHANGELOG.md CHANGED
@@ -10,6 +10,22 @@ nav_order: 6
10
10
 
11
11
  ## main
12
12
 
13
+ ## 3.27.0
14
+
15
+ * [Security] Fix incomplete remediation for CVE-2026-54497 (GHSA-8qw7-6phv-7q6p): reused ViewComponent instances could still leak `with_content` and `renders_one`/`renders_many` slot content from an earlier render into a later render because slot state and content set via `with_content` are populated by the caller before `render_in` runs and were not cleared by the previous per-render reset. Reinstate the `ViewComponent::ReusedInstanceError` guard that raises when a component instance is rendered more than once. Rebuild collection child components per render and dup collection spacer components before each render so that legitimate re-rendering of `Collection`/spacer objects continues to work.
16
+
17
+ *Yazan Balawneh, Cystack.ps*
18
+
19
+ ## 3.26.0
20
+
21
+ * Fix rendering partials from components rendered as a collection when the original view context is explicitly stashed as `nil`.
22
+
23
+ *Justin Coyne, Joel Hawksley*
24
+
25
+ * Restore compatibility with Rails main after `ActionView::Template.template_handler_extensions` and `ActionView::LookupContext#find_template` were removed.
26
+
27
+ *Joel Hawksley*
28
+
13
29
  ## 3.25.0
14
30
 
15
31
  * Support Rails `render_in` options signature. Rails [#50623](https://github.com/rails/rails/pull/50623) changed the `render_in` signature from `render_in(view_context, &block)` to `render_in(view_context, **options, &block)`. `ViewComponent::Base#render_in`, `ViewComponent::Collection#render_in`, and `ViewComponent::Instrumentation#render_in` now accept `**options`, restoring compatibility with Rails main and silencing the deprecation warning.
@@ -83,12 +83,13 @@ module ViewComponent
83
83
  def render_in(view_context, **options, &block)
84
84
  self.class.compile(raise_errors: true)
85
85
 
86
+ __vc_check_reused_instance!
86
87
  __vc_reset_render_state!
87
88
 
88
89
  @view_context = view_context
89
90
  self.__vc_original_view_context =
90
91
  if instance_variable_defined?(:@__vc_pending_original_view_context)
91
- remove_instance_variable(:@__vc_pending_original_view_context)
92
+ remove_instance_variable(:@__vc_pending_original_view_context) || view_context
92
93
  else
93
94
  view_context
94
95
  end
@@ -137,6 +138,7 @@ module ViewComponent
137
138
  end
138
139
  ensure
139
140
  @current_template = old_current_template
141
+ @__vc_rendered = true
140
142
  end
141
143
 
142
144
  # Subclass components that call `super` inside their template code will cause a
@@ -410,7 +412,9 @@ module ViewComponent
410
412
  # state from a previous render. Slot state (`@__vc_set_slots`,
411
413
  # `@__vc_content_set_by_with_content`) is intentionally preserved because it
412
414
  # is populated by callers _before_ `render_in` runs (e.g. via `with_*`
413
- # slot setters or `with_content`).
415
+ # slot setters or `with_content`); reuse of an instance that has slot or
416
+ # `with_content` state is guarded against separately by
417
+ # `__vc_check_reused_instance!`.
414
418
  def __vc_reset_render_state!
415
419
  %i[
416
420
  @__vc_controller
@@ -422,6 +426,17 @@ module ViewComponent
422
426
  end
423
427
  end
424
428
 
429
+ # Raises when a component instance is rendered more than once.
430
+ # Reusing a component instance across renders can leak request-scoped state
431
+ # (controller, helpers, request, view_flow, slot content, `with_content`)
432
+ # from an earlier render into a later one. See
433
+ # `ViewComponent::ReusedInstanceError` and GHSA-8qw7-6phv-7q6p.
434
+ def __vc_check_reused_instance!
435
+ return unless defined?(@__vc_rendered) && @__vc_rendered
436
+
437
+ raise ReusedInstanceError.new(self.class.name)
438
+ end
439
+
425
440
  # Configuration for generators.
426
441
  #
427
442
  # All options under this namespace default to `false` unless otherwise
@@ -72,13 +72,18 @@ module ViewComponent
72
72
  @options.merge(item_options)
73
73
  end
74
74
 
75
+ # Render the spacer through a fresh `dup` so a collection rendered multiple
76
+ # times does not reuse (and trip the single-render guard on) the spacer
77
+ # instance passed by the caller.
75
78
  def rendered_spacer(view_context)
76
- if @spacer_component
77
- @spacer_component.set_original_view_context(__vc_original_view_context) if @spacer_component.respond_to?(:set_original_view_context)
78
- @spacer_component.render_in(view_context)
79
- else
80
- ""
79
+ return "" unless @spacer_component
80
+
81
+ spacer = @spacer_component.dup
82
+ if spacer.instance_variable_defined?(:@__vc_rendered)
83
+ spacer.remove_instance_variable(:@__vc_rendered)
81
84
  end
85
+ spacer.set_original_view_context(__vc_original_view_context) if spacer.respond_to?(:set_original_view_context)
86
+ spacer.render_in(view_context)
82
87
  end
83
88
  end
84
89
  end
@@ -170,7 +170,7 @@ module ViewComponent
170
170
  @templates ||=
171
171
  begin
172
172
  templates = @component.sidecar_files(
173
- ActionView::Template.template_handler_extensions
173
+ template_handler_extensions
174
174
  ).map do |path|
175
175
  # Extract format and variant from template filename
176
176
  this_format, variant =
@@ -225,5 +225,13 @@ module ViewComponent
225
225
  templates
226
226
  end
227
227
  end
228
+
229
+ def template_handler_extensions
230
+ if ActionView::Template.respond_to?(:template_handler_extensions)
231
+ ActionView::Template.template_handler_extensions
232
+ else
233
+ ActionView::Template::Handlers.extensions.map(&:to_s)
234
+ end
235
+ end
228
236
  end
229
237
  end
@@ -175,6 +175,19 @@ module ViewComponent
175
175
  "To fix this issue, pass a value."
176
176
  end
177
177
 
178
+ class ReusedInstanceError < StandardError
179
+ MESSAGE =
180
+ "ViewComponent instances are single-use; a COMPONENT instance was rendered more than once.\n\n" \
181
+ "Reusing a component instance across renders can leak request-scoped state " \
182
+ "(controller, helpers, request, view_flow, slot content, `with_content`) from an earlier render " \
183
+ "into a later one, which has security and correctness implications (GHSA-8qw7-6phv-7q6p).\n\n" \
184
+ "To fix this issue, create a new component instance per render."
185
+
186
+ def initialize(klass_name)
187
+ super(MESSAGE.gsub("COMPONENT", klass_name.to_s))
188
+ end
189
+ end
190
+
178
191
  class TranslateCalledBeforeRenderError < BaseError
179
192
  MESSAGE =
180
193
  "`#translate` can't be used before rendering as it depends " \
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 3
6
- MINOR = 25
6
+ MINOR = 27
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.25.0
4
+ version: 3.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ViewComponent Team
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-06-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -450,8 +449,118 @@ dependencies:
450
449
  - - "~>"
451
450
  - !ruby/object:Gem::Version
452
451
  version: 0.0.1
453
- description:
454
- email:
452
+ - !ruby/object:Gem::Dependency
453
+ name: net-imap
454
+ requirement: !ruby/object:Gem::Requirement
455
+ requirements:
456
+ - - ">="
457
+ - !ruby/object:Gem::Version
458
+ version: '0'
459
+ type: :development
460
+ prerelease: false
461
+ version_requirements: !ruby/object:Gem::Requirement
462
+ requirements:
463
+ - - ">="
464
+ - !ruby/object:Gem::Version
465
+ version: '0'
466
+ - !ruby/object:Gem::Dependency
467
+ name: net-pop
468
+ requirement: !ruby/object:Gem::Requirement
469
+ requirements:
470
+ - - ">="
471
+ - !ruby/object:Gem::Version
472
+ version: '0'
473
+ type: :development
474
+ prerelease: false
475
+ version_requirements: !ruby/object:Gem::Requirement
476
+ requirements:
477
+ - - ">="
478
+ - !ruby/object:Gem::Version
479
+ version: '0'
480
+ - !ruby/object:Gem::Dependency
481
+ name: net-smtp
482
+ requirement: !ruby/object:Gem::Requirement
483
+ requirements:
484
+ - - ">="
485
+ - !ruby/object:Gem::Version
486
+ version: '0'
487
+ type: :development
488
+ prerelease: false
489
+ version_requirements: !ruby/object:Gem::Requirement
490
+ requirements:
491
+ - - ">="
492
+ - !ruby/object:Gem::Version
493
+ version: '0'
494
+ - !ruby/object:Gem::Dependency
495
+ name: base64
496
+ requirement: !ruby/object:Gem::Requirement
497
+ requirements:
498
+ - - ">="
499
+ - !ruby/object:Gem::Version
500
+ version: '0'
501
+ type: :development
502
+ prerelease: false
503
+ version_requirements: !ruby/object:Gem::Requirement
504
+ requirements:
505
+ - - ">="
506
+ - !ruby/object:Gem::Version
507
+ version: '0'
508
+ - !ruby/object:Gem::Dependency
509
+ name: bigdecimal
510
+ requirement: !ruby/object:Gem::Requirement
511
+ requirements:
512
+ - - ">="
513
+ - !ruby/object:Gem::Version
514
+ version: '0'
515
+ type: :development
516
+ prerelease: false
517
+ version_requirements: !ruby/object:Gem::Requirement
518
+ requirements:
519
+ - - ">="
520
+ - !ruby/object:Gem::Version
521
+ version: '0'
522
+ - !ruby/object:Gem::Dependency
523
+ name: drb
524
+ requirement: !ruby/object:Gem::Requirement
525
+ requirements:
526
+ - - ">="
527
+ - !ruby/object:Gem::Version
528
+ version: '0'
529
+ type: :development
530
+ prerelease: false
531
+ version_requirements: !ruby/object:Gem::Requirement
532
+ requirements:
533
+ - - ">="
534
+ - !ruby/object:Gem::Version
535
+ version: '0'
536
+ - !ruby/object:Gem::Dependency
537
+ name: mutex_m
538
+ requirement: !ruby/object:Gem::Requirement
539
+ requirements:
540
+ - - ">="
541
+ - !ruby/object:Gem::Version
542
+ version: '0'
543
+ type: :development
544
+ prerelease: false
545
+ version_requirements: !ruby/object:Gem::Requirement
546
+ requirements:
547
+ - - ">="
548
+ - !ruby/object:Gem::Version
549
+ version: '0'
550
+ - !ruby/object:Gem::Dependency
551
+ name: propshaft
552
+ requirement: !ruby/object:Gem::Requirement
553
+ requirements:
554
+ - - "~>"
555
+ - !ruby/object:Gem::Version
556
+ version: 1.1.0
557
+ type: :development
558
+ prerelease: false
559
+ version_requirements: !ruby/object:Gem::Requirement
560
+ requirements:
561
+ - - "~>"
562
+ - !ruby/object:Gem::Version
563
+ version: 1.1.0
455
564
  executables: []
456
565
  extensions: []
457
566
  extra_rdoc_files: []
@@ -532,7 +641,6 @@ metadata:
532
641
  allowed_push_host: https://rubygems.org
533
642
  source_code_uri: https://github.com/viewcomponent/view_component
534
643
  changelog_uri: https://github.com/ViewComponent/view_component/blob/main/docs/CHANGELOG.md
535
- post_install_message:
536
644
  rdoc_options: []
537
645
  require_paths:
538
646
  - lib
@@ -547,8 +655,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
547
655
  - !ruby/object:Gem::Version
548
656
  version: '0'
549
657
  requirements: []
550
- rubygems_version: 3.0.3.1
551
- signing_key:
658
+ rubygems_version: 3.6.9
552
659
  specification_version: 4
553
660
  summary: A framework for building reusable, testable & encapsulated view components
554
661
  in Ruby on Rails.