actionview 8.0.0.1 → 8.0.2
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 +54 -0
- data/lib/action_view/base.rb +6 -9
- data/lib/action_view/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +2 -2
- data/lib/action_view/helpers/form_helper.rb +32 -32
- data/lib/action_view/helpers/output_safety_helper.rb +1 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/layouts.rb +6 -6
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb.rb +45 -37
- metadata +12 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc81c16e4d502ce1736e2ff17c85dbb50ed6209d6ded187af4f846d05540f551
|
4
|
+
data.tar.gz: faa7c34dff4cfc391389c56b52afd0cbbbdbaf5ee7805ae3e1d1fd78940f1195
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e9c0c527c580719aea26c3a8499d1b1b82e4da5074271403c0060d0d96b604e23fe953ae8ede37d901ba7830fd3700a82297be2d29d574845eb79b559277d0f
|
7
|
+
data.tar.gz: 24a3fc73c41d00476204519044e278f8c545db961ac02e88d810325f6cc7d831d410e203e1691767b1cca6672c0ab2d0c5b19179276c47a672b8489827d0545d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,57 @@
|
|
1
|
+
## Rails 8.0.2 (March 12, 2025) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 8.0.2 (March 12, 2025) ##
|
7
|
+
|
8
|
+
* Respect `html_options[:form]` when `collection_checkboxes` generates the
|
9
|
+
hidden `<input>`.
|
10
|
+
|
11
|
+
*Riccardo Odone*
|
12
|
+
|
13
|
+
* Layouts have access to local variables passed to `render`.
|
14
|
+
|
15
|
+
This fixes #31680 which was a regression in Rails 5.1.
|
16
|
+
|
17
|
+
*Mike Dalessio*
|
18
|
+
|
19
|
+
* Argument errors related to strict locals in templates now raise an
|
20
|
+
`ActionView::StrictLocalsError`, and all other argument errors are reraised as-is.
|
21
|
+
|
22
|
+
Previously, any `ArgumentError` raised during template rendering was swallowed during strict
|
23
|
+
local error handling, so that an `ArgumentError` unrelated to strict locals (e.g., a helper
|
24
|
+
method invoked with incorrect arguments) would be replaced by a similar `ArgumentError` with an
|
25
|
+
unrelated backtrace, making it difficult to debug templates.
|
26
|
+
|
27
|
+
Now, any `ArgumentError` unrelated to strict locals is reraised, preserving the original
|
28
|
+
backtrace for developers.
|
29
|
+
|
30
|
+
Also note that `ActionView::StrictLocalsError` is a subclass of `ArgumentError`, so any existing
|
31
|
+
code that rescues `ArgumentError` will continue to work.
|
32
|
+
|
33
|
+
Fixes #52227.
|
34
|
+
|
35
|
+
*Mike Dalessio*
|
36
|
+
|
37
|
+
* Fix stack overflow error in dependency tracker when dealing with circular dependencies
|
38
|
+
|
39
|
+
*Jean Boussier*
|
40
|
+
|
41
|
+
## Rails 8.0.1 (December 13, 2024) ##
|
42
|
+
|
43
|
+
* Fix a crash in ERB template error highlighting when the error occurs on a
|
44
|
+
line in the compiled template that is past the end of the source template.
|
45
|
+
|
46
|
+
*Martin Emde*
|
47
|
+
|
48
|
+
* Improve reliability of ERB template error highlighting.
|
49
|
+
Fix infinite loops and crashes in highlighting and
|
50
|
+
improve tolerance for alternate ERB handlers.
|
51
|
+
|
52
|
+
*Martin Emde*
|
53
|
+
|
54
|
+
|
1
55
|
## Rails 8.0.0.1 (December 10, 2024) ##
|
2
56
|
|
3
57
|
* No changes.
|
data/lib/action_view/base.rb
CHANGED
@@ -267,15 +267,12 @@ module ActionView # :nodoc:
|
|
267
267
|
begin
|
268
268
|
public_send(method, locals, buffer, **locals, &block)
|
269
269
|
rescue ArgumentError => argument_error
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
gsub("no keywords accepted", "no locals accepted").
|
277
|
-
concat(" for #{@current_template.short_identifier}")
|
278
|
-
)
|
270
|
+
public_send_line = __LINE__ - 2
|
271
|
+
frame = argument_error.backtrace_locations[1]
|
272
|
+
if frame.path == __FILE__ && frame.lineno == public_send_line
|
273
|
+
raise StrictLocalsError.new(argument_error, @current_template)
|
274
|
+
end
|
275
|
+
raise
|
279
276
|
end
|
280
277
|
else
|
281
278
|
public_send(method, locals, buffer, &block)
|
data/lib/action_view/digestor.rb
CHANGED
@@ -107,8 +107,12 @@ module ActionView
|
|
107
107
|
end.join("-")
|
108
108
|
end
|
109
109
|
|
110
|
-
def to_dep_map
|
111
|
-
|
110
|
+
def to_dep_map(seen = Set.new.compare_by_identity)
|
111
|
+
if seen.add?(self)
|
112
|
+
children.any? ? { name => children.map { |c| c.to_dep_map(seen) } } : name
|
113
|
+
else # the tree has a cycle
|
114
|
+
name
|
115
|
+
end
|
112
116
|
end
|
113
117
|
end
|
114
118
|
|
@@ -197,7 +197,7 @@ module ActionView
|
|
197
197
|
CachingRegistry.caching?
|
198
198
|
end
|
199
199
|
|
200
|
-
# Raises
|
200
|
+
# Raises UncacheableFragmentError when called from within a +cache+ block.
|
201
201
|
#
|
202
202
|
# Useful to denote helper methods that can't participate in fragment caching:
|
203
203
|
#
|
@@ -206,7 +206,7 @@ module ActionView
|
|
206
206
|
# "#{project.name} - #{Time.now}"
|
207
207
|
# end
|
208
208
|
#
|
209
|
-
# # Which will then raise if used within a
|
209
|
+
# # Which will then raise if used within a `cache` block:
|
210
210
|
# <% cache project do %>
|
211
211
|
# <%= project_name_with_time(project) %>
|
212
212
|
# <% end %>
|
@@ -31,7 +31,7 @@ module ActionView
|
|
31
31
|
# of the resource should show the current values of those attributes.
|
32
32
|
#
|
33
33
|
# In \Rails, this is usually achieved by creating the form using either
|
34
|
-
#
|
34
|
+
# #form_with or #form_for and a number of related helper methods. These
|
35
35
|
# methods generate an appropriate <tt>form</tt> tag and yield a form
|
36
36
|
# builder object that knows the model the form is about. Input fields are
|
37
37
|
# created by calling methods defined on the form builder, which means they
|
@@ -42,7 +42,7 @@ module ActionView
|
|
42
42
|
#
|
43
43
|
# For example, to create a new person you typically set up a new instance of
|
44
44
|
# +Person+ in the <tt>PeopleController#new</tt> action, <tt>@person</tt>, and
|
45
|
-
# in the view template pass that object to
|
45
|
+
# in the view template pass that object to #form_with or #form_for:
|
46
46
|
#
|
47
47
|
# <%= form_with model: @person do |f| %>
|
48
48
|
# <%= f.label :first_name %>:
|
@@ -209,7 +209,7 @@ module ActionView
|
|
209
209
|
# are designed to work with an object as base, like
|
210
210
|
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
211
211
|
#
|
212
|
-
# ===
|
212
|
+
# === +form_for+ with a model object
|
213
213
|
#
|
214
214
|
# In the examples above, the object to be created or edited was
|
215
215
|
# represented by a symbol passed to +form_for+, and we noted that
|
@@ -364,7 +364,7 @@ module ActionView
|
|
364
364
|
#
|
365
365
|
# === Removing hidden model id's
|
366
366
|
#
|
367
|
-
# The form_for method automatically includes the model id as a hidden field in the form.
|
367
|
+
# The +form_for+ method automatically includes the model id as a hidden field in the form.
|
368
368
|
# This is used to maintain the correlation between the form data and its associated model.
|
369
369
|
# Some ORM systems do not use IDs on nested models so in this case you want to be able
|
370
370
|
# to disable the hidden id.
|
@@ -784,12 +784,12 @@ module ActionView
|
|
784
784
|
end
|
785
785
|
end
|
786
786
|
|
787
|
-
# Creates a scope around a specific model object like
|
787
|
+
# Creates a scope around a specific model object like #form_with, but
|
788
788
|
# doesn't create the form tags themselves. This makes +fields_for+
|
789
789
|
# suitable for specifying additional model objects in the same form.
|
790
790
|
#
|
791
|
-
# Although the usage and purpose of +fields_for+ is similar to
|
792
|
-
# its method signature is slightly different. Like
|
791
|
+
# Although the usage and purpose of +fields_for+ is similar to #form_with's,
|
792
|
+
# its method signature is slightly different. Like #form_with, it yields
|
793
793
|
# a FormBuilder object associated with a particular model object to a block,
|
794
794
|
# and within the block allows methods to be called on the builder to
|
795
795
|
# generate fields associated with the model object. Fields may reflect
|
@@ -848,7 +848,7 @@ module ActionView
|
|
848
848
|
# === Nested Attributes Examples
|
849
849
|
#
|
850
850
|
# When the object belonging to the current scope has a nested attribute
|
851
|
-
# writer for a certain attribute, fields_for will yield a new scope
|
851
|
+
# writer for a certain attribute, +fields_for+ will yield a new scope
|
852
852
|
# for that attribute. This allows you to create forms that set or change
|
853
853
|
# the attributes of a parent object and its associations in one go.
|
854
854
|
#
|
@@ -937,7 +937,7 @@ module ActionView
|
|
937
937
|
# end
|
938
938
|
#
|
939
939
|
# Note that the <tt>projects_attributes=</tt> writer method is in fact
|
940
|
-
# required for fields_for to correctly identify <tt>:projects</tt> as a
|
940
|
+
# required for +fields_for+ to correctly identify <tt>:projects</tt> as a
|
941
941
|
# collection, and the correct indices to be set in the form markup.
|
942
942
|
#
|
943
943
|
# When projects is already an association on Person you can use
|
@@ -949,7 +949,7 @@ module ActionView
|
|
949
949
|
# end
|
950
950
|
#
|
951
951
|
# This model can now be used with a nested fields_for. The block given to
|
952
|
-
# the nested fields_for call will be repeated for each instance in the
|
952
|
+
# the nested +fields_for+ call will be repeated for each instance in the
|
953
953
|
# collection:
|
954
954
|
#
|
955
955
|
# <%= form_with model: @person do |person_form| %>
|
@@ -1021,10 +1021,10 @@ module ActionView
|
|
1021
1021
|
# ...
|
1022
1022
|
# <% end %>
|
1023
1023
|
#
|
1024
|
-
# Note that fields_for will automatically generate a hidden field
|
1024
|
+
# Note that +fields_for+ will automatically generate a hidden field
|
1025
1025
|
# to store the ID of the record if it responds to <tt>persisted?</tt>.
|
1026
1026
|
# There are circumstances where this hidden field is not needed and you
|
1027
|
-
# can pass <tt>include_id: false</tt> to prevent fields_for from
|
1027
|
+
# can pass <tt>include_id: false</tt> to prevent +fields_for+ from
|
1028
1028
|
# rendering it automatically.
|
1029
1029
|
def fields_for(record_name, record_object = nil, options = {}, &block)
|
1030
1030
|
options = { model: record_object, allow_method_names_outside_object: false, skip_default_ids: false }.merge!(options)
|
@@ -1033,7 +1033,7 @@ module ActionView
|
|
1033
1033
|
end
|
1034
1034
|
|
1035
1035
|
# Scopes input fields with either an explicit scope or model.
|
1036
|
-
# Like
|
1036
|
+
# Like #form_with does with <tt>:scope</tt> or <tt>:model</tt>,
|
1037
1037
|
# except it doesn't output the form tags.
|
1038
1038
|
#
|
1039
1039
|
# # Using a scope prefixes the input field names:
|
@@ -1048,7 +1048,7 @@ module ActionView
|
|
1048
1048
|
# <% end %>
|
1049
1049
|
# # => <input type="text" name="comment[body]" value="full bodied">
|
1050
1050
|
#
|
1051
|
-
# # Using
|
1051
|
+
# # Using `fields` with `form_with`:
|
1052
1052
|
# <%= form_with model: @article do |form| %>
|
1053
1053
|
# <%= form.text_field :title %>
|
1054
1054
|
#
|
@@ -1057,13 +1057,13 @@ module ActionView
|
|
1057
1057
|
# <% end %>
|
1058
1058
|
# <% end %>
|
1059
1059
|
#
|
1060
|
-
# Much like
|
1060
|
+
# Much like #form_with a FormBuilder instance associated with the scope
|
1061
1061
|
# or model is yielded, so any generated field names are prefixed with
|
1062
1062
|
# either the passed scope or the scope inferred from the <tt>:model</tt>.
|
1063
1063
|
#
|
1064
1064
|
# === Mixing with other form helpers
|
1065
1065
|
#
|
1066
|
-
# While
|
1066
|
+
# While #form_with uses a FormBuilder object it's possible to mix and
|
1067
1067
|
# match the stand-alone FormHelper methods and methods
|
1068
1068
|
# from FormTagHelper:
|
1069
1069
|
#
|
@@ -1221,7 +1221,7 @@ module ActionView
|
|
1221
1221
|
# hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
|
1222
1222
|
# shown.
|
1223
1223
|
#
|
1224
|
-
# Using this method inside a
|
1224
|
+
# Using this method inside a #form_with block will set the enclosing form's encoding to <tt>multipart/form-data</tt>.
|
1225
1225
|
#
|
1226
1226
|
# ==== Options
|
1227
1227
|
# * Creates standard HTML attributes for the tag.
|
@@ -1326,7 +1326,7 @@ module ActionView
|
|
1326
1326
|
# the elements of the array. For each item with a checked check box you
|
1327
1327
|
# get an extra ghost item with only that attribute, assigned to "0".
|
1328
1328
|
#
|
1329
|
-
# In that case it is preferable to either use
|
1329
|
+
# In that case it is preferable to either use FormTagHelper#checkbox_tag or to use
|
1330
1330
|
# hashes instead of arrays.
|
1331
1331
|
#
|
1332
1332
|
# ==== Examples
|
@@ -1632,7 +1632,7 @@ module ActionView
|
|
1632
1632
|
#
|
1633
1633
|
# A +FormBuilder+ object is associated with a particular model object and
|
1634
1634
|
# allows you to generate fields associated with the model object. The
|
1635
|
-
# +FormBuilder+ object is yielded when using
|
1635
|
+
# +FormBuilder+ object is yielded when using #form_with or #fields_for.
|
1636
1636
|
# For example:
|
1637
1637
|
#
|
1638
1638
|
# <%= form_with model: @person do |person_form| %>
|
@@ -1770,7 +1770,7 @@ module ActionView
|
|
1770
1770
|
# <% end %>
|
1771
1771
|
#
|
1772
1772
|
# In the example above, the <tt><input type="text"></tt> element built by
|
1773
|
-
# the call to
|
1773
|
+
# the call to #text_field declares an
|
1774
1774
|
# <tt>aria-describedby</tt> attribute referencing the <tt><span></tt>
|
1775
1775
|
# element, sharing a common <tt>id</tt> root (<tt>article_title</tt>, in this
|
1776
1776
|
# case).
|
@@ -2033,12 +2033,12 @@ module ActionView
|
|
2033
2033
|
end
|
2034
2034
|
alias_method :text_area, :textarea
|
2035
2035
|
|
2036
|
-
# Creates a scope around a specific model object like
|
2036
|
+
# Creates a scope around a specific model object like #form_with, but
|
2037
2037
|
# doesn't create the form tags themselves. This makes +fields_for+
|
2038
2038
|
# suitable for specifying additional model objects in the same form.
|
2039
2039
|
#
|
2040
|
-
# Although the usage and purpose of +fields_for+ is similar to
|
2041
|
-
# its method signature is slightly different. Like
|
2040
|
+
# Although the usage and purpose of +fields_for+ is similar to #form_with's,
|
2041
|
+
# its method signature is slightly different. Like #form_with, it yields
|
2042
2042
|
# a FormBuilder object associated with a particular model object to a block,
|
2043
2043
|
# and within the block allows methods to be called on the builder to
|
2044
2044
|
# generate fields associated with the model object. Fields may reflect
|
@@ -2109,7 +2109,7 @@ module ActionView
|
|
2109
2109
|
# === Nested Attributes Examples
|
2110
2110
|
#
|
2111
2111
|
# When the object belonging to the current scope has a nested attribute
|
2112
|
-
# writer for a certain attribute, fields_for will yield a new scope
|
2112
|
+
# writer for a certain attribute, +fields_for+ will yield a new scope
|
2113
2113
|
# for that attribute. This allows you to create forms that set or change
|
2114
2114
|
# the attributes of a parent object and its associations in one go.
|
2115
2115
|
#
|
@@ -2140,7 +2140,7 @@ module ActionView
|
|
2140
2140
|
# end
|
2141
2141
|
# end
|
2142
2142
|
#
|
2143
|
-
# This model can now be used with a nested fields_for
|
2143
|
+
# This model can now be used with a nested +fields_for+, like so:
|
2144
2144
|
#
|
2145
2145
|
# <%= form_with model: @person do |person_form| %>
|
2146
2146
|
# ...
|
@@ -2198,7 +2198,7 @@ module ActionView
|
|
2198
2198
|
# end
|
2199
2199
|
#
|
2200
2200
|
# Note that the <tt>projects_attributes=</tt> writer method is in fact
|
2201
|
-
# required for fields_for to correctly identify <tt>:projects</tt> as a
|
2201
|
+
# required for +fields_for+ to correctly identify <tt>:projects</tt> as a
|
2202
2202
|
# collection, and the correct indices to be set in the form markup.
|
2203
2203
|
#
|
2204
2204
|
# When projects is already an association on Person you can use
|
@@ -2209,8 +2209,8 @@ module ActionView
|
|
2209
2209
|
# accepts_nested_attributes_for :projects
|
2210
2210
|
# end
|
2211
2211
|
#
|
2212
|
-
# This model can now be used with a nested fields_for
|
2213
|
-
# the nested fields_for call will be repeated for each instance in the
|
2212
|
+
# This model can now be used with a nested +fields_for+. The block given to
|
2213
|
+
# the nested +fields_for+ call will be repeated for each instance in the
|
2214
2214
|
# collection:
|
2215
2215
|
#
|
2216
2216
|
# <%= form_with model: @person do |person_form| %>
|
@@ -2282,10 +2282,10 @@ module ActionView
|
|
2282
2282
|
# ...
|
2283
2283
|
# <% end %>
|
2284
2284
|
#
|
2285
|
-
# Note that fields_for will automatically generate a hidden field
|
2285
|
+
# Note that +fields_for+ will automatically generate a hidden field
|
2286
2286
|
# to store the ID of the record. There are circumstances where this
|
2287
2287
|
# hidden field is not needed and you can pass <tt>include_id: false</tt>
|
2288
|
-
# to prevent fields_for from rendering it automatically.
|
2288
|
+
# to prevent +fields_for+ from rendering it automatically.
|
2289
2289
|
def fields_for(record_name, record_object = nil, fields_options = nil, &block)
|
2290
2290
|
fields_options, record_object = record_object, nil if fields_options.nil? && record_object.is_a?(Hash) && record_object.extractable_options?
|
2291
2291
|
fields_options ||= {}
|
@@ -2451,7 +2451,7 @@ module ActionView
|
|
2451
2451
|
# the elements of the array. For each item with a checked check box you
|
2452
2452
|
# get an extra ghost item with only that attribute, assigned to "0".
|
2453
2453
|
#
|
2454
|
-
# In that case it is preferable to either use
|
2454
|
+
# In that case it is preferable to either use FormTagHelper#checkbox_tag or to use
|
2455
2455
|
# hashes instead of arrays.
|
2456
2456
|
#
|
2457
2457
|
# ==== Examples
|
@@ -2525,7 +2525,7 @@ module ActionView
|
|
2525
2525
|
# hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
|
2526
2526
|
# shown.
|
2527
2527
|
#
|
2528
|
-
# Using this method inside a
|
2528
|
+
# Using this method inside a #form_with block will set the enclosing form's encoding to <tt>multipart/form-data</tt>.
|
2529
2529
|
#
|
2530
2530
|
# ==== Options
|
2531
2531
|
# * Creates standard HTML attributes for the tag.
|
@@ -38,8 +38,7 @@ module ActionView # :nodoc:
|
|
38
38
|
|
39
39
|
# Converts the array to a comma-separated sentence where the last element is
|
40
40
|
# joined by the connector word. This is the html_safe-aware version of
|
41
|
-
# ActiveSupport's
|
42
|
-
#
|
41
|
+
# ActiveSupport's Array#to_sentence.
|
43
42
|
def to_sentence(array, options = {})
|
44
43
|
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
45
44
|
|
@@ -24,6 +24,12 @@ module ActionView
|
|
24
24
|
#
|
25
25
|
# Custom sanitization rules can also be provided.
|
26
26
|
#
|
27
|
+
# <b>Warning</b>: Adding disallowed tags or attributes to the allowlists may introduce
|
28
|
+
# vulnerabilities into your application. Please rely on the default allowlists whenever
|
29
|
+
# possible, because they are curated to maintain security and safety. If you think that the
|
30
|
+
# default allowlists should be expanded, please {open an issue on the rails-html-sanitizer
|
31
|
+
# project}[https://github.com/rails/rails-html-sanitizer/issues].
|
32
|
+
#
|
27
33
|
# Please note that sanitizing user-provided text does not guarantee that the
|
28
34
|
# resulting markup is valid or even well-formed.
|
29
35
|
#
|
@@ -106,7 +106,8 @@ module ActionView
|
|
106
106
|
|
107
107
|
def hidden_field
|
108
108
|
hidden_name = @html_options[:name] || hidden_field_name
|
109
|
-
|
109
|
+
options = { id: nil, form: @html_options[:form] }
|
110
|
+
@template_object.hidden_field_tag(hidden_name, "", options)
|
110
111
|
end
|
111
112
|
|
112
113
|
def hidden_field_name
|
data/lib/action_view/layouts.rb
CHANGED
@@ -284,7 +284,7 @@ module ActionView
|
|
284
284
|
silence_redefinition_of_method(:_layout)
|
285
285
|
|
286
286
|
prefixes = /\blayouts/.match?(_implied_layout_name) ? [] : ["layouts"]
|
287
|
-
default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false,
|
287
|
+
default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false, keys, { formats: formats }).first || super"
|
288
288
|
name_clause = if name
|
289
289
|
default_behavior
|
290
290
|
else
|
@@ -325,7 +325,7 @@ module ActionView
|
|
325
325
|
|
326
326
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
327
327
|
# frozen_string_literal: true
|
328
|
-
def _layout(lookup_context, formats)
|
328
|
+
def _layout(lookup_context, formats, keys)
|
329
329
|
if _conditional_layout?
|
330
330
|
#{layout_definition}
|
331
331
|
else
|
@@ -389,8 +389,8 @@ module ActionView
|
|
389
389
|
case name
|
390
390
|
when String then _normalize_layout(name)
|
391
391
|
when Proc then name
|
392
|
-
when true then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, true) }
|
393
|
-
when :default then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, false) }
|
392
|
+
when true then Proc.new { |lookup_context, formats, keys| _default_layout(lookup_context, formats, keys, true) }
|
393
|
+
when :default then Proc.new { |lookup_context, formats, keys| _default_layout(lookup_context, formats, keys, false) }
|
394
394
|
when false, nil then nil
|
395
395
|
else
|
396
396
|
raise ArgumentError,
|
@@ -412,9 +412,9 @@ module ActionView
|
|
412
412
|
#
|
413
413
|
# ==== Returns
|
414
414
|
# * <tt>template</tt> - The template object for the default layout (or +nil+)
|
415
|
-
def _default_layout(lookup_context, formats, require_layout = false)
|
415
|
+
def _default_layout(lookup_context, formats, keys, require_layout = false)
|
416
416
|
begin
|
417
|
-
value = _layout(lookup_context, formats) if action_has_layout?
|
417
|
+
value = _layout(lookup_context, formats, keys) if action_has_layout?
|
418
418
|
rescue NameError => e
|
419
419
|
raise e, "Could not render layout: #{e.message}"
|
420
420
|
end
|
@@ -94,7 +94,7 @@ module ActionView
|
|
94
94
|
# # <%= render partial: "accounts/account", locals: { account: @account} %>
|
95
95
|
# <%= render partial: @account %>
|
96
96
|
#
|
97
|
-
# # @posts is an array of Post instances, so every post record returns 'posts/post' on
|
97
|
+
# # @posts is an array of Post instances, so every post record returns 'posts/post' on #to_partial_path,
|
98
98
|
# # that's why we can replace:
|
99
99
|
# # <%= render partial: "posts/post", collection: @posts %>
|
100
100
|
# <%= render partial: @posts %>
|
@@ -114,7 +114,7 @@ module ActionView
|
|
114
114
|
# # <%= render partial: "accounts/account", locals: { account: @account} %>
|
115
115
|
# <%= render @account %>
|
116
116
|
#
|
117
|
-
# # @posts is an array of Post instances, so every post record returns 'posts/post' on
|
117
|
+
# # @posts is an array of Post instances, so every post record returns 'posts/post' on #to_partial_path,
|
118
118
|
# # that's why we can replace:
|
119
119
|
# # <%= render partial: "posts/post", collection: @posts %>
|
120
120
|
# <%= render @posts %>
|
@@ -99,14 +99,14 @@ module ActionView
|
|
99
99
|
if layout.start_with?("/")
|
100
100
|
raise ArgumentError, "Rendering layouts from an absolute path is not supported."
|
101
101
|
else
|
102
|
-
@lookup_context.find_template(layout, nil, false,
|
102
|
+
@lookup_context.find_template(layout, nil, false, keys, details)
|
103
103
|
end
|
104
104
|
rescue ActionView::MissingTemplate
|
105
105
|
all_details = @details.merge(formats: @lookup_context.default_formats)
|
106
|
-
raise unless template_exists?(layout, nil, false,
|
106
|
+
raise unless template_exists?(layout, nil, false, keys, **all_details)
|
107
107
|
end
|
108
108
|
when Proc
|
109
|
-
resolve_layout(layout.call(@lookup_context, formats), keys, formats)
|
109
|
+
resolve_layout(layout.call(@lookup_context, formats, keys), keys, formats)
|
110
110
|
else
|
111
111
|
layout
|
112
112
|
end
|
@@ -27,6 +27,17 @@ module ActionView
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
class StrictLocalsError < ArgumentError # :nodoc:
|
31
|
+
def initialize(argument_error, template)
|
32
|
+
message = argument_error.message.
|
33
|
+
gsub("unknown keyword:", "unknown local:").
|
34
|
+
gsub("missing keyword:", "missing local:").
|
35
|
+
gsub("no keywords accepted", "no locals accepted").
|
36
|
+
concat(" for #{template.short_identifier}")
|
37
|
+
super(message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
30
41
|
class MissingTemplate < ActionViewError # :nodoc:
|
31
42
|
attr_reader :path, :paths, :prefixes, :partial
|
32
43
|
|
@@ -42,7 +42,9 @@ module ActionView
|
|
42
42
|
# source location inside the template.
|
43
43
|
def translate_location(spot, backtrace_location, source)
|
44
44
|
# Tokenize the source line
|
45
|
-
|
45
|
+
source_lines = source.lines
|
46
|
+
return nil if source_lines.size < backtrace_location.lineno
|
47
|
+
tokens = ::ERB::Util.tokenize(source_lines[backtrace_location.lineno - 1])
|
46
48
|
new_first_column = find_offset(spot[:snippet], tokens, spot[:first_column])
|
47
49
|
lineno_delta = spot[:first_lineno] - backtrace_location.lineno
|
48
50
|
spot[:first_lineno] -= lineno_delta
|
@@ -51,7 +53,7 @@ module ActionView
|
|
51
53
|
column_delta = spot[:first_column] - new_first_column
|
52
54
|
spot[:first_column] -= column_delta
|
53
55
|
spot[:last_column] -= column_delta
|
54
|
-
spot[:script_lines] =
|
56
|
+
spot[:script_lines] = source_lines
|
55
57
|
|
56
58
|
spot
|
57
59
|
rescue NotImplementedError, LocationParsingError
|
@@ -105,51 +107,57 @@ module ActionView
|
|
105
107
|
raise WrongEncodingError.new(string, string.encoding)
|
106
108
|
end
|
107
109
|
|
110
|
+
# Find which token in the source template spans the byte range that
|
111
|
+
# contains the error_column, then return the offset compared to the
|
112
|
+
# original source template.
|
113
|
+
#
|
114
|
+
# Iterate consecutive pairs of CODE or TEXT tokens, requiring
|
115
|
+
# a match of the first token before matching either token.
|
116
|
+
#
|
117
|
+
# For example, if we want to find tokens A, B, C, we do the following:
|
118
|
+
# 1. Find a match for A: test error_column or advance scanner.
|
119
|
+
# 2. Find a match for B or A:
|
120
|
+
# a. If B: start over with next token set (B, C).
|
121
|
+
# b. If A: test error_column or advance scanner.
|
122
|
+
# c. Otherwise: Advance 1 byte
|
123
|
+
#
|
124
|
+
# Prioritize matching the next token over the current token once
|
125
|
+
# a match for the current token has been found. This is to prevent
|
126
|
+
# the current token from looping past the next token if they both
|
127
|
+
# match (i.e. if the current token is a single space character).
|
108
128
|
def find_offset(compiled, source_tokens, error_column)
|
109
129
|
compiled = StringScanner.new(compiled)
|
130
|
+
offset_source_tokens(source_tokens).each_cons(2) do |(name, str, offset), (_, next_str, _)|
|
131
|
+
matched_str = false
|
110
132
|
|
111
|
-
|
133
|
+
until compiled.eos?
|
134
|
+
if matched_str && next_str && compiled.match?(next_str)
|
135
|
+
break
|
136
|
+
elsif compiled.match?(str)
|
137
|
+
matched_str = true
|
112
138
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
when :TEXT
|
117
|
-
loop do
|
118
|
-
break if compiled.match?(str)
|
119
|
-
compiled.getch
|
120
|
-
end
|
121
|
-
raise LocationParsingError unless compiled.scan(str)
|
122
|
-
when :CODE
|
123
|
-
if compiled.pos > error_column
|
124
|
-
raise LocationParsingError, "We went too far"
|
125
|
-
end
|
139
|
+
if name == :CODE && compiled.pos <= error_column && compiled.pos + str.bytesize >= error_column
|
140
|
+
return error_column - compiled.pos + offset
|
141
|
+
end
|
126
142
|
|
127
|
-
|
128
|
-
offset = error_column - compiled.pos
|
129
|
-
return passed_tokens.map(&:last).join.bytesize + offset
|
143
|
+
compiled.pos += str.bytesize
|
130
144
|
else
|
131
|
-
|
132
|
-
raise LocationParsingError, "Couldn't find code snippet"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
when :OPEN
|
136
|
-
next_tok = source_tokens.first.last
|
137
|
-
loop do
|
138
|
-
break if compiled.match?(next_tok)
|
139
|
-
compiled.getch
|
145
|
+
compiled.pos += 1
|
140
146
|
end
|
141
|
-
when :CLOSE
|
142
|
-
next_tok = source_tokens.first.last
|
143
|
-
loop do
|
144
|
-
break if compiled.match?(next_tok)
|
145
|
-
compiled.getch
|
146
|
-
end
|
147
|
-
else
|
148
|
-
raise LocationParsingError, "Not implemented: #{tok.first}"
|
149
147
|
end
|
148
|
+
end
|
149
|
+
|
150
|
+
raise LocationParsingError, "Couldn't find code snippet"
|
151
|
+
end
|
150
152
|
|
151
|
-
|
153
|
+
def offset_source_tokens(source_tokens)
|
154
|
+
source_offset = 0
|
155
|
+
with_offset = source_tokens.filter_map do |(name, str)|
|
156
|
+
result = [name, str, source_offset] if name == :CODE || name == :TEXT
|
157
|
+
source_offset += str.bytesize
|
158
|
+
result
|
152
159
|
end
|
160
|
+
with_offset << [:EOS, nil, source_offset]
|
153
161
|
end
|
154
162
|
end
|
155
163
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionview
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.0.
|
4
|
+
version: 8.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: activesupport
|
@@ -16,14 +15,14 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - '='
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version: 8.0.
|
18
|
+
version: 8.0.2
|
20
19
|
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
23
|
- - '='
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version: 8.0.
|
25
|
+
version: 8.0.2
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
27
|
name: builder
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,28 +85,28 @@ dependencies:
|
|
86
85
|
requirements:
|
87
86
|
- - '='
|
88
87
|
- !ruby/object:Gem::Version
|
89
|
-
version: 8.0.
|
88
|
+
version: 8.0.2
|
90
89
|
type: :development
|
91
90
|
prerelease: false
|
92
91
|
version_requirements: !ruby/object:Gem::Requirement
|
93
92
|
requirements:
|
94
93
|
- - '='
|
95
94
|
- !ruby/object:Gem::Version
|
96
|
-
version: 8.0.
|
95
|
+
version: 8.0.2
|
97
96
|
- !ruby/object:Gem::Dependency
|
98
97
|
name: activemodel
|
99
98
|
requirement: !ruby/object:Gem::Requirement
|
100
99
|
requirements:
|
101
100
|
- - '='
|
102
101
|
- !ruby/object:Gem::Version
|
103
|
-
version: 8.0.
|
102
|
+
version: 8.0.2
|
104
103
|
type: :development
|
105
104
|
prerelease: false
|
106
105
|
version_requirements: !ruby/object:Gem::Requirement
|
107
106
|
requirements:
|
108
107
|
- - '='
|
109
108
|
- !ruby/object:Gem::Version
|
110
|
-
version: 8.0.
|
109
|
+
version: 8.0.2
|
111
110
|
description: Simple, battle-tested conventions and helpers for building web pages.
|
112
111
|
email: david@loudthinking.com
|
113
112
|
executables: []
|
@@ -247,12 +246,11 @@ licenses:
|
|
247
246
|
- MIT
|
248
247
|
metadata:
|
249
248
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
250
|
-
changelog_uri: https://github.com/rails/rails/blob/v8.0.
|
251
|
-
documentation_uri: https://api.rubyonrails.org/v8.0.
|
249
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.0.2/actionview/CHANGELOG.md
|
250
|
+
documentation_uri: https://api.rubyonrails.org/v8.0.2/
|
252
251
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
253
|
-
source_code_uri: https://github.com/rails/rails/tree/v8.0.
|
252
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.0.2/actionview
|
254
253
|
rubygems_mfa_required: 'true'
|
255
|
-
post_install_message:
|
256
254
|
rdoc_options: []
|
257
255
|
require_paths:
|
258
256
|
- lib
|
@@ -268,8 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
268
266
|
version: '0'
|
269
267
|
requirements:
|
270
268
|
- none
|
271
|
-
rubygems_version: 3.
|
272
|
-
signing_key:
|
269
|
+
rubygems_version: 3.6.2
|
273
270
|
specification_version: 4
|
274
271
|
summary: Rendering framework putting the V in MVC (part of Rails).
|
275
272
|
test_files: []
|