actionview 7.2.3 → 8.1.3
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 +4 -4
- data/CHANGELOG.md +112 -121
- data/lib/action_view/base.rb +5 -2
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/dependency_tracker/erb_tracker.rb +37 -28
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +2 -19
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +7 -1
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +21 -2
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -2
- data/lib/action_view/helpers/cache_helper.rb +8 -0
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +6 -2
- data/lib/action_view/helpers/date_helper.rb +20 -3
- data/lib/action_view/helpers/form_helper.rb +76 -76
- data/lib/action_view/helpers/form_options_helper.rb +33 -32
- data/lib/action_view/helpers/form_tag_helper.rb +35 -25
- data/lib/action_view/helpers/javascript_helper.rb +5 -1
- data/lib/action_view/helpers/number_helper.rb +14 -0
- data/lib/action_view/helpers/rendering_helper.rb +160 -50
- data/lib/action_view/helpers/sanitize_helper.rb +6 -0
- data/lib/action_view/helpers/tag_helper.rb +62 -75
- data/lib/action_view/helpers/tags/base.rb +11 -9
- data/lib/action_view/helpers/tags/check_box.rb +9 -3
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
- data/lib/action_view/helpers/tags/file_field.rb +7 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +1 -1
- data/lib/action_view/helpers/tags/label.rb +3 -10
- data/lib/action_view/helpers/tags/radio_button.rb +1 -1
- data/lib/action_view/helpers/tags/select.rb +6 -1
- data/lib/action_view/helpers/tags/select_renderer.rb +6 -4
- data/lib/action_view/helpers/tags/text_area.rb +1 -1
- data/lib/action_view/helpers/tags/text_field.rb +1 -1
- data/lib/action_view/helpers/translation_helper.rb +6 -1
- data/lib/action_view/helpers/url_helper.rb +39 -13
- data/lib/action_view/layouts.rb +1 -1
- data/lib/action_view/locale/en.yml +3 -0
- data/lib/action_view/log_subscriber.rb +1 -4
- data/lib/action_view/railtie.rb +12 -1
- data/lib/action_view/record_identifier.rb +22 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +13 -1
- data/lib/action_view/render_parser/ripper_render_parser.rb +10 -1
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +5 -1
- data/lib/action_view/renderer/partial_renderer.rb +16 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +8 -2
- data/lib/action_view/rendering.rb +2 -3
- data/lib/action_view/structured_event_subscriber.rb +97 -0
- data/lib/action_view/template/error.rb +7 -3
- data/lib/action_view/template/handlers/erb/erubi.rb +1 -1
- data/lib/action_view/template/handlers/erb.rb +37 -12
- data/lib/action_view/template/raw_file.rb +4 -0
- data/lib/action_view/template/resolver.rb +0 -1
- data/lib/action_view/template.rb +9 -4
- data/lib/action_view/test_case.rb +50 -52
- data/lib/action_view.rb +3 -0
- metadata +14 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96267f5fb9e3f51b3f9532cf10d78e0454480729b75a758b6df1bf6bb903384f
|
|
4
|
+
data.tar.gz: f7befef7e6c94a2dda6868cd265cbb4009576883d881a9f28195d68649b9511c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd4eb208e63b468bd0b97bda5b8202a7954e6545e05b6a600fcd0a1d703303e99ff2ffbd929ec63142e118267a61cc1cd7f62f5deed6b47ed05e1e6bed50291b
|
|
7
|
+
data.tar.gz: 98fcb31d4441433ac6bd216aec193446d4e06c6116e038bf8d6c5166275937b8301879c3b2d454a1cf86fe9ed6a373898d7f808b35ef4881885231762dcba5b4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,200 +1,191 @@
|
|
|
1
|
-
## Rails
|
|
1
|
+
## Rails 8.1.3 (March 24, 2026) ##
|
|
2
2
|
|
|
3
|
-
* Fix
|
|
3
|
+
* Fix encoding errors for string locals containing non-ASCII characters.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
javascript_include_tag "application", type: :module
|
|
7
|
-
javascript_include_tag "application", type: "module"
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
Previously, only the string value was recoginized.
|
|
11
|
-
|
|
12
|
-
*Jean Boussier*
|
|
13
|
-
|
|
14
|
-
* Fix `excerpt` helper with non-whitespace separator.
|
|
15
|
-
|
|
16
|
-
*Jonathan Hefner*
|
|
17
|
-
|
|
18
|
-
* Respect `html_options[:form]` when `collection_checkboxes` generates the
|
|
19
|
-
hidden `<input>`.
|
|
20
|
-
|
|
21
|
-
*Riccardo Odone*
|
|
5
|
+
*Kataoka Katsuki*
|
|
22
6
|
|
|
23
|
-
*
|
|
7
|
+
* Fix collection caching to only forward `expires_in` argument if explicitly set.
|
|
24
8
|
|
|
25
|
-
|
|
9
|
+
*Pieter Visser*
|
|
26
10
|
|
|
27
|
-
|
|
11
|
+
## Rails 8.1.2.1 (March 23, 2026) ##
|
|
28
12
|
|
|
29
|
-
*
|
|
30
|
-
`ActionView::StrictLocalsError`, and all other argument errors are reraised as-is.
|
|
13
|
+
* Fix possible XSS in DebugExceptions middleware
|
|
31
14
|
|
|
32
|
-
|
|
33
|
-
local error handling, so that an `ArgumentError` unrelated to strict locals (e.g., a helper
|
|
34
|
-
method invoked with incorrect arguments) would be replaced by a similar `ArgumentError` with an
|
|
35
|
-
unrelated backtrace, making it difficult to debug templates.
|
|
15
|
+
[CVE-2026-33167]
|
|
36
16
|
|
|
37
|
-
|
|
38
|
-
backtrace for developers.
|
|
17
|
+
*John Hawthorn*
|
|
39
18
|
|
|
40
|
-
|
|
41
|
-
code that rescues `ArgumentError` will continue to work.
|
|
19
|
+
* Skip blank attribute names in tag helpers to avoid generating invalid HTML.
|
|
42
20
|
|
|
43
|
-
|
|
21
|
+
[CVE-2026-33168]
|
|
44
22
|
|
|
45
23
|
*Mike Dalessio*
|
|
46
24
|
|
|
47
|
-
* Fix stack overflow error in dependency tracker when dealing with circular dependencies
|
|
48
|
-
|
|
49
|
-
*Jean Boussier*
|
|
50
|
-
|
|
51
|
-
* Fix a crash in ERB template error highlighting when the error occurs on a
|
|
52
|
-
line in the compiled template that is past the end of the source template.
|
|
53
|
-
|
|
54
|
-
*Martin Emde*
|
|
55
|
-
|
|
56
|
-
* Improve reliability of ERB template error highlighting.
|
|
57
|
-
Fix infinite loops and crashes in highlighting and
|
|
58
|
-
improve tolerance for alternate ERB handlers.
|
|
59
|
-
|
|
60
|
-
*Martin Emde*
|
|
61
25
|
|
|
26
|
+
## Rails 8.1.2 (January 08, 2026) ##
|
|
62
27
|
|
|
63
|
-
|
|
28
|
+
* Fix `file_field` to join mime types with a comma when provided as Array
|
|
64
29
|
|
|
65
|
-
|
|
30
|
+
```ruby
|
|
31
|
+
file_field(:article, :image, accept: ['image/png', 'image/gif', 'image/jpeg'])
|
|
32
|
+
```
|
|
66
33
|
|
|
34
|
+
Now behaves likes:
|
|
67
35
|
|
|
68
|
-
|
|
36
|
+
```
|
|
37
|
+
file_field(:article, :image, accept: 'image/png,image/gif,image/jpeg')
|
|
38
|
+
```
|
|
69
39
|
|
|
70
|
-
*
|
|
40
|
+
*Bogdan Gusiev*
|
|
71
41
|
|
|
42
|
+
* Fix strict locals parsing to handle multiline definitions.
|
|
72
43
|
|
|
73
|
-
|
|
44
|
+
*Said Kaldybaev*
|
|
74
45
|
|
|
75
|
-
*
|
|
46
|
+
* Fix `content_security_policy_nonce` error in mailers when using `content_security_policy_nonce_auto` setting.
|
|
76
47
|
|
|
48
|
+
The `content_security_policy_nonce helper` is provided by `ActionController::ContentSecurityPolicy`, and it relies on `request.content_security_policy_nonc`e. Mailers lack both the module and the request object.
|
|
77
49
|
|
|
78
|
-
|
|
50
|
+
*Jarrett Lusso*
|
|
79
51
|
|
|
80
|
-
* No changes.
|
|
81
52
|
|
|
53
|
+
## Rails 8.1.1 (October 28, 2025) ##
|
|
82
54
|
|
|
83
|
-
|
|
55
|
+
* Respect `remove_hidden_field_autocomplete` config in form builder `hidden_field`.
|
|
84
56
|
|
|
85
|
-
*
|
|
57
|
+
*Rafael Mendonça França*
|
|
86
58
|
|
|
87
59
|
|
|
88
|
-
## Rails
|
|
60
|
+
## Rails 8.1.0 (October 22, 2025) ##
|
|
89
61
|
|
|
90
|
-
*
|
|
62
|
+
* The BEGIN template annotation/comment was previously printed on the same line as the following element. We now insert a newline inside the comment so it spans two lines without adding visible whitespace to the HTML output to enhance readability.
|
|
91
63
|
|
|
64
|
+
Before:
|
|
65
|
+
```
|
|
66
|
+
<!-- BEGIN /Users/siaw23/Desktop/rails/actionview/test/fixtures/actionpack/test/greeting.html.erb --><p>This is grand!</p>
|
|
67
|
+
```
|
|
92
68
|
|
|
93
|
-
|
|
69
|
+
After:
|
|
70
|
+
```
|
|
71
|
+
<!-- BEGIN /Users/siaw23/Desktop/rails/actionview/test/fixtures/actionpack/test/greeting.html.erb
|
|
72
|
+
--><p>This is grand!</p>
|
|
73
|
+
```
|
|
74
|
+
*Emmanuel Hayford*
|
|
94
75
|
|
|
95
|
-
*
|
|
76
|
+
* Add structured events for Action View:
|
|
77
|
+
- `action_view.render_template`
|
|
78
|
+
- `action_view.render_partial`
|
|
79
|
+
- `action_view.render_layout`
|
|
80
|
+
- `action_view.render_collection`
|
|
81
|
+
- `action_view.render_start`
|
|
96
82
|
|
|
97
|
-
|
|
98
|
-
hash.
|
|
83
|
+
*Gannon McGibbon*
|
|
99
84
|
|
|
100
|
-
|
|
85
|
+
* Fix label with `for` option not getting prefixed by form `namespace` value
|
|
101
86
|
|
|
102
|
-
*
|
|
87
|
+
*Abeid Ahmed*, *Hartley McGuire*
|
|
103
88
|
|
|
104
|
-
|
|
105
|
-
# Before
|
|
106
|
-
Completed 200 OK in 3804ms (Views: 41.0ms | ActiveRecord: 33.5ms | Allocations: 112788)
|
|
89
|
+
* Add `fetchpriority` to Link headers to match HTML generated by `preload_link_tag`.
|
|
107
90
|
|
|
108
|
-
|
|
109
|
-
Completed 200 OK in 3804ms (Views: 41.0ms | ActiveRecord: 33.5ms (2 queries, 1 cached) | Allocations: 112788)
|
|
110
|
-
```
|
|
91
|
+
*Guillermo Iguaran*
|
|
111
92
|
|
|
112
|
-
|
|
93
|
+
* Add CSP `nonce` to Link headers generated by `preload_link_tag`.
|
|
113
94
|
|
|
114
|
-
*
|
|
95
|
+
*Alexander Gitter*
|
|
115
96
|
|
|
116
|
-
|
|
97
|
+
* Allow `current_page?` to match against specific HTTP method(s) with a `method:` option.
|
|
117
98
|
|
|
118
|
-
*
|
|
99
|
+
*Ben Sheldon*
|
|
119
100
|
|
|
120
|
-
|
|
101
|
+
* Remove `autocomplete="off"` on hidden inputs generated by the following
|
|
102
|
+
tags:
|
|
121
103
|
|
|
122
|
-
*
|
|
104
|
+
* `form_tag`, `token_tag`, `method_tag`
|
|
123
105
|
|
|
124
|
-
|
|
106
|
+
As well as the hidden parameter fields included in `button_to`,
|
|
107
|
+
`check_box`, `select` (with `multiple`) and `file_field` forms.
|
|
125
108
|
|
|
126
|
-
*
|
|
109
|
+
*nkulway*
|
|
127
110
|
|
|
128
|
-
*
|
|
111
|
+
* Enable configuring the strategy for tracking dependencies between Action
|
|
112
|
+
View templates.
|
|
129
113
|
|
|
130
|
-
|
|
114
|
+
The existing `:regex` strategy is kept as the default, but with
|
|
115
|
+
`load_defaults 8.1` the strategy will be `:ruby` (using a real Ruby parser).
|
|
131
116
|
|
|
132
|
-
*
|
|
117
|
+
*Hartley McGuire*
|
|
133
118
|
|
|
134
|
-
*
|
|
119
|
+
* Introduce `relative_time_in_words` helper
|
|
135
120
|
|
|
136
|
-
|
|
121
|
+
```ruby
|
|
122
|
+
relative_time_in_words(3.minutes.from_now) # => "in 3 minutes"
|
|
123
|
+
relative_time_in_words(3.minutes.ago) # => "3 minutes ago"
|
|
124
|
+
relative_time_in_words(10.seconds.ago, include_seconds: true) # => "less than 10 seconds ago"
|
|
125
|
+
```
|
|
137
126
|
|
|
138
|
-
*
|
|
127
|
+
*Matheus Richard*
|
|
139
128
|
|
|
140
|
-
|
|
129
|
+
* Make `nonce: false` remove the nonce attribute from `javascript_tag`, `javascript_include_tag`, and `stylesheet_link_tag`.
|
|
141
130
|
|
|
142
|
-
*
|
|
131
|
+
*francktrouillez*
|
|
143
132
|
|
|
144
|
-
|
|
133
|
+
* Add `dom_target` helper to create `dom_id`-like strings from an unlimited
|
|
134
|
+
number of objects.
|
|
145
135
|
|
|
146
|
-
*
|
|
136
|
+
*Ben Sheldon*
|
|
147
137
|
|
|
148
|
-
|
|
138
|
+
* Respect `html_options[:form]` when `collection_checkboxes` generates the
|
|
139
|
+
hidden `<input>`.
|
|
149
140
|
|
|
150
|
-
*
|
|
141
|
+
*Riccardo Odone*
|
|
151
142
|
|
|
152
|
-
|
|
143
|
+
* Layouts have access to local variables passed to `render`.
|
|
153
144
|
|
|
154
|
-
|
|
145
|
+
This fixes #31680 which was a regression in Rails 5.1.
|
|
155
146
|
|
|
156
|
-
*
|
|
147
|
+
*Mike Dalessio*
|
|
157
148
|
|
|
158
|
-
*
|
|
149
|
+
* Argument errors related to strict locals in templates now raise an
|
|
150
|
+
`ActionView::StrictLocalsError`, and all other argument errors are reraised as-is.
|
|
159
151
|
|
|
160
|
-
|
|
152
|
+
Previously, any `ArgumentError` raised during template rendering was swallowed during strict
|
|
153
|
+
local error handling, so that an `ArgumentError` unrelated to strict locals (e.g., a helper
|
|
154
|
+
method invoked with incorrect arguments) would be replaced by a similar `ArgumentError` with an
|
|
155
|
+
unrelated backtrace, making it difficult to debug templates.
|
|
161
156
|
|
|
162
|
-
|
|
157
|
+
Now, any `ArgumentError` unrelated to strict locals is reraised, preserving the original
|
|
158
|
+
backtrace for developers.
|
|
163
159
|
|
|
164
|
-
|
|
165
|
-
|
|
160
|
+
Also note that `ActionView::StrictLocalsError` is a subclass of `ArgumentError`, so any existing
|
|
161
|
+
code that rescues `ArgumentError` will continue to work.
|
|
166
162
|
|
|
167
|
-
|
|
163
|
+
Fixes #52227.
|
|
168
164
|
|
|
169
|
-
*
|
|
165
|
+
*Mike Dalessio*
|
|
170
166
|
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
* Improve error highlighting of multi-line methods in ERB templates or
|
|
168
|
+
templates where the error occurs within a do-end block.
|
|
173
169
|
|
|
174
|
-
*
|
|
170
|
+
*Martin Emde*
|
|
175
171
|
|
|
176
|
-
*
|
|
172
|
+
* Fix a crash in ERB template error highlighting when the error occurs on a
|
|
173
|
+
line in the compiled template that is past the end of the source template.
|
|
177
174
|
|
|
178
|
-
|
|
179
|
-
specification. If an invalid HTML tag name is provided, the method raises an `ArgumentError`
|
|
180
|
-
with an appropriate error message.
|
|
175
|
+
*Martin Emde*
|
|
181
176
|
|
|
182
|
-
|
|
177
|
+
* Improve reliability of ERB template error highlighting.
|
|
178
|
+
Fix infinite loops and crashes in highlighting and
|
|
179
|
+
improve tolerance for alternate ERB handlers.
|
|
183
180
|
|
|
184
|
-
|
|
185
|
-
# Raises ArgumentError: Invalid HTML5 tag name: 12p
|
|
186
|
-
content_tag("12p") # Starting with a number
|
|
181
|
+
*Martin Emde*
|
|
187
182
|
|
|
188
|
-
|
|
189
|
-
content_tag("") # Empty tag name
|
|
183
|
+
* Allow `hidden_field` and `hidden_field_tag` to accept a custom autocomplete value.
|
|
190
184
|
|
|
191
|
-
|
|
192
|
-
tag("div/") # Contains a solidus
|
|
185
|
+
*brendon*
|
|
193
186
|
|
|
194
|
-
|
|
195
|
-
tag("image file") # Contains a space
|
|
196
|
-
```
|
|
187
|
+
* Add a new configuration `content_security_policy_nonce_auto` for automatically adding a nonce to the tags affected by the directives specified by the `content_security_policy_nonce_directives` configuration option.
|
|
197
188
|
|
|
198
|
-
*
|
|
189
|
+
*francktrouillez*
|
|
199
190
|
|
|
200
|
-
Please check [
|
|
191
|
+
Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/actionview/CHANGELOG.md) for previous changes.
|
data/lib/action_view/base.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "active_support/core_ext/module/attr_internal"
|
|
|
4
4
|
require "active_support/core_ext/module/attribute_accessors"
|
|
5
5
|
require "active_support/ordered_options"
|
|
6
6
|
require "action_view/log_subscriber"
|
|
7
|
+
require "action_view/structured_event_subscriber"
|
|
7
8
|
require "action_view/helpers"
|
|
8
9
|
require "action_view/context"
|
|
9
10
|
require "action_view/template"
|
|
@@ -181,6 +182,10 @@ module ActionView # :nodoc:
|
|
|
181
182
|
class_attribute :_routes
|
|
182
183
|
class_attribute :logger
|
|
183
184
|
|
|
185
|
+
# Specify whether to omit autocomplete="off" on hidden inputs generated by helpers.
|
|
186
|
+
# Configured via `config.action_view.remove_hidden_field_autocomplete`
|
|
187
|
+
cattr_accessor :remove_hidden_field_autocomplete, default: false
|
|
188
|
+
|
|
184
189
|
class << self
|
|
185
190
|
delegate :erb_trim_mode=, to: "ActionView::Template::Handlers::ERB"
|
|
186
191
|
|
|
@@ -242,8 +247,6 @@ module ActionView # :nodoc:
|
|
|
242
247
|
# :startdoc:
|
|
243
248
|
|
|
244
249
|
def initialize(lookup_context, assigns, controller) # :nodoc:
|
|
245
|
-
@_config = ActiveSupport::InheritableOptions.new
|
|
246
|
-
|
|
247
250
|
@lookup_context = lookup_context
|
|
248
251
|
|
|
249
252
|
@view_renderer = ActionView::Renderer.new @lookup_context
|
data/lib/action_view/buffers.rb
CHANGED
|
@@ -74,7 +74,7 @@ module ActionView
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def dependencies
|
|
77
|
-
render_dependencies + explicit_dependencies
|
|
77
|
+
WildcardResolver.new(@view_paths, render_dependencies + explicit_dependencies).resolve
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
attr_reader :name, :template
|
|
@@ -90,15 +90,15 @@ module ActionView
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
def render_dependencies
|
|
93
|
-
|
|
94
|
-
render_calls = source.
|
|
93
|
+
dependencies = []
|
|
94
|
+
render_calls = source.scan(/<%(?:(?:(?!<%).)*?\brender\b((?:(?!%>).)*?))%>/m).flatten
|
|
95
95
|
|
|
96
96
|
render_calls.each do |arguments|
|
|
97
|
-
add_dependencies(
|
|
98
|
-
add_dependencies(
|
|
97
|
+
add_dependencies(dependencies, arguments, LAYOUT_DEPENDENCY)
|
|
98
|
+
add_dependencies(dependencies, arguments, RENDER_ARGUMENTS)
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
dependencies
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
def add_dependencies(render_dependencies, arguments, pattern)
|
|
@@ -116,12 +116,37 @@ module ActionView
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def add_static_dependency(dependencies, dependency, quote_type)
|
|
119
|
-
if quote_type == '"'
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
if quote_type == '"' && dependency.include?('#{')
|
|
120
|
+
scanner = StringScanner.new(dependency)
|
|
121
|
+
|
|
122
|
+
wildcard_dependency = +""
|
|
123
|
+
|
|
124
|
+
while !scanner.eos?
|
|
125
|
+
if scanner.scan_until(/\#{/)
|
|
126
|
+
unmatched_brackets = 1
|
|
127
|
+
wildcard_dependency << scanner.pre_match
|
|
128
|
+
|
|
129
|
+
while unmatched_brackets > 0 && !scanner.eos?
|
|
130
|
+
found = scanner.scan_until(/[{}]/)
|
|
131
|
+
return unless found
|
|
132
|
+
|
|
133
|
+
case scanner.matched
|
|
134
|
+
when "{"
|
|
135
|
+
unmatched_brackets += 1
|
|
136
|
+
when "}"
|
|
137
|
+
unmatched_brackets -= 1
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
wildcard_dependency << "*"
|
|
142
|
+
else
|
|
143
|
+
wildcard_dependency << scanner.rest
|
|
144
|
+
scanner.terminate
|
|
145
|
+
end
|
|
146
|
+
end
|
|
123
147
|
|
|
124
|
-
|
|
148
|
+
dependencies << wildcard_dependency
|
|
149
|
+
elsif dependency
|
|
125
150
|
if dependency.include?("/")
|
|
126
151
|
dependencies << dependency
|
|
127
152
|
else
|
|
@@ -130,24 +155,8 @@ module ActionView
|
|
|
130
155
|
end
|
|
131
156
|
end
|
|
132
157
|
|
|
133
|
-
def resolve_directories(wildcard_dependencies)
|
|
134
|
-
return [] unless @view_paths
|
|
135
|
-
return [] if wildcard_dependencies.empty?
|
|
136
|
-
|
|
137
|
-
# Remove trailing "/*"
|
|
138
|
-
prefixes = wildcard_dependencies.map { |query| query[0..-3] }
|
|
139
|
-
|
|
140
|
-
@view_paths.flat_map(&:all_template_paths).uniq.filter_map { |path|
|
|
141
|
-
path.to_s if prefixes.include?(path.prefix)
|
|
142
|
-
}.sort
|
|
143
|
-
end
|
|
144
|
-
|
|
145
158
|
def explicit_dependencies
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
wildcards, explicits = dependencies.partition { |dependency| dependency.end_with?("/*") }
|
|
149
|
-
|
|
150
|
-
(explicits + resolve_directories(wildcards)).uniq
|
|
159
|
+
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
|
151
160
|
end
|
|
152
161
|
end
|
|
153
162
|
end
|
|
@@ -10,7 +10,7 @@ module ActionView
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def dependencies
|
|
13
|
-
render_dependencies + explicit_dependencies
|
|
13
|
+
WildcardResolver.new(view_paths, render_dependencies + explicit_dependencies).resolve
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def self.supports_view_paths? # :nodoc:
|
|
@@ -31,29 +31,12 @@ module ActionView
|
|
|
31
31
|
compiled_source = template.handler.call(template, template.source)
|
|
32
32
|
|
|
33
33
|
@parser_class.new(@name, compiled_source).render_calls.filter_map do |render_call|
|
|
34
|
-
next if render_call.end_with?("/_")
|
|
35
34
|
render_call.gsub(%r|/_|, "/")
|
|
36
35
|
end
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
def explicit_dependencies
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
wildcards, explicits = dependencies.partition { |dependency| dependency.end_with?("/*") }
|
|
43
|
-
|
|
44
|
-
(explicits + resolve_directories(wildcards)).uniq
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def resolve_directories(wildcard_dependencies)
|
|
48
|
-
return [] unless view_paths
|
|
49
|
-
return [] if wildcard_dependencies.empty?
|
|
50
|
-
|
|
51
|
-
# Remove trailing "/*"
|
|
52
|
-
prefixes = wildcard_dependencies.map { |query| query[0..-3] }
|
|
53
|
-
|
|
54
|
-
view_paths.flat_map(&:all_template_paths).uniq.filter_map { |path|
|
|
55
|
-
path.to_s if prefixes.include?(path.prefix)
|
|
56
|
-
}.sort
|
|
39
|
+
template.source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
|
57
40
|
end
|
|
58
41
|
end
|
|
59
42
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionView
|
|
4
|
+
class DependencyTracker # :nodoc:
|
|
5
|
+
class WildcardResolver # :nodoc:
|
|
6
|
+
def initialize(view_paths, dependencies)
|
|
7
|
+
@view_paths = view_paths
|
|
8
|
+
|
|
9
|
+
@wildcard_dependencies, @explicit_dependencies =
|
|
10
|
+
dependencies.partition { |dependency| dependency.end_with?("/*") }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resolve
|
|
14
|
+
return explicit_dependencies.uniq if !view_paths || wildcard_dependencies.empty?
|
|
15
|
+
|
|
16
|
+
(explicit_dependencies + resolved_wildcard_dependencies).uniq
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
attr_reader :explicit_dependencies, :wildcard_dependencies, :view_paths
|
|
21
|
+
|
|
22
|
+
def resolved_wildcard_dependencies
|
|
23
|
+
# Remove trailing "/*"
|
|
24
|
+
prefixes = wildcard_dependencies.map { |query| query[0..-3] }
|
|
25
|
+
|
|
26
|
+
view_paths.flat_map(&:all_template_paths).uniq.filter_map { |path|
|
|
27
|
+
path.to_s if prefixes.include?(path.prefix)
|
|
28
|
+
}.sort
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -10,6 +10,7 @@ module ActionView
|
|
|
10
10
|
|
|
11
11
|
autoload :ERBTracker
|
|
12
12
|
autoload :RubyTracker
|
|
13
|
+
autoload :WildcardResolver
|
|
13
14
|
|
|
14
15
|
@trackers = Concurrent::Map.new
|
|
15
16
|
|
|
@@ -35,6 +36,11 @@ module ActionView
|
|
|
35
36
|
@trackers.delete(handler)
|
|
36
37
|
end
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
case ActionView.render_tracker
|
|
40
|
+
when :ruby
|
|
41
|
+
register_tracker :erb, RubyTracker
|
|
42
|
+
else
|
|
43
|
+
register_tracker :erb, ERBTracker
|
|
44
|
+
end
|
|
39
45
|
end
|
|
40
46
|
end
|
|
@@ -26,6 +26,8 @@ module ActionView
|
|
|
26
26
|
mattr_accessor :image_decoding
|
|
27
27
|
mattr_accessor :preload_links_header
|
|
28
28
|
mattr_accessor :apply_stylesheet_media_default
|
|
29
|
+
mattr_accessor :auto_include_nonce_for_scripts
|
|
30
|
+
mattr_accessor :auto_include_nonce_for_styles
|
|
29
31
|
|
|
30
32
|
# Returns an HTML script tag for each of the +sources+ provided.
|
|
31
33
|
#
|
|
@@ -127,6 +129,7 @@ module ActionView
|
|
|
127
129
|
preload_link = "<#{href}>; rel=#{rel}; as=script"
|
|
128
130
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
|
129
131
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
|
132
|
+
preload_link += "; nonce=#{content_security_policy_nonce}" if options["nonce"] == true
|
|
130
133
|
preload_link += "; nopush" if nopush
|
|
131
134
|
preload_links << preload_link
|
|
132
135
|
end
|
|
@@ -134,8 +137,10 @@ module ActionView
|
|
|
134
137
|
"src" => href,
|
|
135
138
|
"crossorigin" => crossorigin
|
|
136
139
|
}.merge!(options)
|
|
137
|
-
if tag_options["nonce"] == true
|
|
140
|
+
if tag_options["nonce"] == true || (!tag_options.key?("nonce") && auto_include_nonce_for_scripts)
|
|
138
141
|
tag_options["nonce"] = content_security_policy_nonce
|
|
142
|
+
elsif tag_options["nonce"] == false
|
|
143
|
+
tag_options.delete("nonce")
|
|
139
144
|
end
|
|
140
145
|
content_tag("script", "", tag_options)
|
|
141
146
|
}.join("\n").html_safe
|
|
@@ -215,6 +220,7 @@ module ActionView
|
|
|
215
220
|
preload_link = "<#{href}>; rel=preload; as=style"
|
|
216
221
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
|
217
222
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
|
223
|
+
preload_link += "; nonce=#{content_security_policy_nonce}" if options["nonce"] == true
|
|
218
224
|
preload_link += "; nopush" if nopush
|
|
219
225
|
preload_links << preload_link
|
|
220
226
|
end
|
|
@@ -223,8 +229,10 @@ module ActionView
|
|
|
223
229
|
"crossorigin" => crossorigin,
|
|
224
230
|
"href" => href
|
|
225
231
|
}.merge!(options)
|
|
226
|
-
if tag_options["nonce"] == true
|
|
232
|
+
if tag_options["nonce"] == true || (!tag_options.key?("nonce") && auto_include_nonce_for_styles && respond_to?(:content_security_policy_nonce))
|
|
227
233
|
tag_options["nonce"] = content_security_policy_nonce
|
|
234
|
+
elsif tag_options["nonce"] == false
|
|
235
|
+
tag_options.delete("nonce")
|
|
228
236
|
end
|
|
229
237
|
|
|
230
238
|
if apply_stylesheet_media_default && tag_options["media"].blank?
|
|
@@ -360,8 +368,16 @@ module ActionView
|
|
|
360
368
|
crossorigin = options.delete(:crossorigin)
|
|
361
369
|
crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
|
|
362
370
|
integrity = options[:integrity]
|
|
371
|
+
fetchpriority = options.delete(:fetchpriority)
|
|
363
372
|
nopush = options.delete(:nopush) || false
|
|
364
373
|
rel = mime_type == "module" || mime_type == :module ? "modulepreload" : "preload"
|
|
374
|
+
add_nonce = content_security_policy_nonce &&
|
|
375
|
+
respond_to?(:request) &&
|
|
376
|
+
request.content_security_policy_nonce_directives&.include?("#{as_type}-src")
|
|
377
|
+
|
|
378
|
+
if add_nonce
|
|
379
|
+
options[:nonce] = content_security_policy_nonce
|
|
380
|
+
end
|
|
365
381
|
|
|
366
382
|
link_tag = tag.link(
|
|
367
383
|
rel: rel,
|
|
@@ -369,12 +385,15 @@ module ActionView
|
|
|
369
385
|
as: as_type,
|
|
370
386
|
type: mime_type,
|
|
371
387
|
crossorigin: crossorigin,
|
|
388
|
+
fetchpriority: fetchpriority,
|
|
372
389
|
**options.symbolize_keys)
|
|
373
390
|
|
|
374
391
|
preload_link = "<#{href}>; rel=#{rel}; as=#{as_type}"
|
|
375
392
|
preload_link += "; type=#{mime_type}" if mime_type
|
|
376
393
|
preload_link += "; crossorigin=#{crossorigin}" if crossorigin
|
|
394
|
+
preload_link += "; fetchpriority=#{fetchpriority}" if fetchpriority
|
|
377
395
|
preload_link += "; integrity=#{integrity}" if integrity
|
|
396
|
+
preload_link += "; nonce=#{content_security_policy_nonce}" if add_nonce
|
|
378
397
|
preload_link += "; nopush" if nopush
|
|
379
398
|
|
|
380
399
|
send_preload_links_header([preload_link])
|