actionview 7.1.2 → 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 +51 -382
- data/lib/action_view/base.rb +25 -11
- data/lib/action_view/cache_expiry.rb +9 -3
- data/lib/action_view/dependency_tracker/erb_tracker.rb +36 -27
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +2 -1
- data/lib/action_view/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -2
- data/lib/action_view/helpers/cache_helper.rb +14 -6
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +282 -273
- data/lib/action_view/helpers/form_options_helper.rb +23 -21
- data/lib/action_view/helpers/form_tag_helper.rb +104 -69
- data/lib/action_view/helpers/number_helper.rb +35 -329
- data/lib/action_view/helpers/output_safety_helper.rb +5 -6
- data/lib/action_view/helpers/rendering_helper.rb +160 -50
- data/lib/action_view/helpers/sanitize_helper.rb +31 -14
- data/lib/action_view/helpers/tag_helper.rb +196 -19
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/text_helper.rb +125 -69
- data/lib/action_view/helpers/url_helper.rb +6 -80
- data/lib/action_view/layouts.rb +11 -13
- data/lib/action_view/log_subscriber.rb +8 -4
- data/lib/action_view/railtie.rb +0 -1
- data/lib/action_view/record_identifier.rb +1 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
- data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +162 -10
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -1
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/rendering.rb +6 -7
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb.rb +45 -37
- data/lib/action_view/template/renderable.rb +7 -1
- data/lib/action_view/template/resolver.rb +0 -3
- data/lib/action_view/template.rb +46 -12
- data/lib/action_view/test_case.rb +14 -16
- data/lib/action_view/unbound_template.rb +4 -4
- data/lib/action_view.rb +1 -1
- metadata +17 -19
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +0 -59
- data/lib/assets/compiled/rails-ujs.js +0 -777
|
@@ -41,21 +41,25 @@ module ActionView
|
|
|
41
41
|
include OutputSafetyHelper
|
|
42
42
|
|
|
43
43
|
# The preferred method of outputting text in your views is to use the
|
|
44
|
-
#
|
|
44
|
+
# <tt><%= "text" %></tt> eRuby syntax. The regular +puts+ and +print+ methods
|
|
45
45
|
# do not operate as expected in an eRuby code block. If you absolutely must
|
|
46
|
-
# output text within a non-output code block (i.e.,
|
|
46
|
+
# output text within a non-output code block (i.e., <tt><% %></tt>), you
|
|
47
|
+
# can use the +concat+ method.
|
|
48
|
+
#
|
|
49
|
+
# <% concat "hello" %> is equivalent to <%= "hello" %>
|
|
47
50
|
#
|
|
48
51
|
# <%
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# if logged_in
|
|
53
|
-
# concat "Logged in!"
|
|
54
|
-
# else
|
|
55
|
-
# concat link_to('login', action: :login)
|
|
56
|
-
# end
|
|
57
|
-
# # will either display "Logged in!" or a login link
|
|
52
|
+
# unless signed_in?
|
|
53
|
+
# concat link_to("Sign In", action: :sign_in)
|
|
54
|
+
# end
|
|
58
55
|
# %>
|
|
56
|
+
#
|
|
57
|
+
# is equivalent to
|
|
58
|
+
#
|
|
59
|
+
# <% unless signed_in? %>
|
|
60
|
+
# <%= link_to "Sign In", action: :sign_in %>
|
|
61
|
+
# <% end %>
|
|
62
|
+
#
|
|
59
63
|
def concat(string)
|
|
60
64
|
output_buffer << string
|
|
61
65
|
end
|
|
@@ -64,17 +68,36 @@ module ActionView
|
|
|
64
68
|
output_buffer.respond_to?(:safe_concat) ? output_buffer.safe_concat(string) : concat(string)
|
|
65
69
|
end
|
|
66
70
|
|
|
67
|
-
# Truncates
|
|
68
|
-
#
|
|
69
|
-
#
|
|
71
|
+
# Truncates +text+ if it is longer than a specified +:length+. If +text+
|
|
72
|
+
# is truncated, an omission marker will be appended to the result for a
|
|
73
|
+
# total length not exceeding +:length+.
|
|
74
|
+
#
|
|
75
|
+
# You can also pass a block to render and append extra content after the
|
|
76
|
+
# omission marker when +text+ is truncated. However, this content _can_
|
|
77
|
+
# cause the total length to exceed +:length+ characters.
|
|
78
|
+
#
|
|
79
|
+
# The result will be escaped unless <tt>escape: false</tt> is specified.
|
|
80
|
+
# In any case, the result will be marked HTML-safe. Care should be taken
|
|
81
|
+
# if +text+ might contain HTML tags or entities, because truncation could
|
|
82
|
+
# produce invalid HTML, such as unbalanced or incomplete tags.
|
|
70
83
|
#
|
|
71
|
-
#
|
|
84
|
+
# ==== Options
|
|
85
|
+
#
|
|
86
|
+
# [+:length+]
|
|
87
|
+
# The maximum number of characters that should be returned, excluding
|
|
88
|
+
# any extra content from the block. Defaults to 30.
|
|
72
89
|
#
|
|
73
|
-
#
|
|
90
|
+
# [+:omission+]
|
|
91
|
+
# The string to append after truncating. Defaults to <tt>"..."</tt>.
|
|
74
92
|
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
93
|
+
# [+:separator+]
|
|
94
|
+
# A string or regexp used to find a breaking point at which to truncate.
|
|
95
|
+
# By default, truncation can occur at any character in +text+.
|
|
96
|
+
#
|
|
97
|
+
# [+:escape+]
|
|
98
|
+
# Whether to escape the result. Defaults to true.
|
|
99
|
+
#
|
|
100
|
+
# ==== Examples
|
|
78
101
|
#
|
|
79
102
|
# truncate("Once upon a time in a world far far away")
|
|
80
103
|
# # => "Once upon a time in a world..."
|
|
@@ -95,7 +118,7 @@ module ActionView
|
|
|
95
118
|
# # => "<p>Once upon a time in a wo..."
|
|
96
119
|
#
|
|
97
120
|
# truncate("Once upon a time in a world far far away") { link_to "Continue", "#" }
|
|
98
|
-
# # => "Once upon a time in a
|
|
121
|
+
# # => "Once upon a time in a world...<a href=\"#\">Continue</a>"
|
|
99
122
|
def truncate(text, options = {}, &block)
|
|
100
123
|
if text
|
|
101
124
|
length = options.fetch(:length, 30)
|
|
@@ -107,33 +130,47 @@ module ActionView
|
|
|
107
130
|
end
|
|
108
131
|
end
|
|
109
132
|
|
|
110
|
-
# Highlights
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
#
|
|
133
|
+
# Highlights occurrences of +phrases+ in +text+ by formatting them with a
|
|
134
|
+
# highlighter string. +phrases+ can be one or more strings or regular
|
|
135
|
+
# expressions. The result will be marked HTML safe. By default, +text+ is
|
|
136
|
+
# sanitized before highlighting to prevent possible XSS attacks.
|
|
137
|
+
#
|
|
138
|
+
# If a block is specified, it will be used instead of the highlighter
|
|
139
|
+
# string. Each occurrence of a phrase will be passed to the block, and its
|
|
140
|
+
# return value will be inserted into the final result.
|
|
141
|
+
#
|
|
142
|
+
# ==== Options
|
|
143
|
+
#
|
|
144
|
+
# [+:highlighter+]
|
|
145
|
+
# The highlighter string. Uses <tt>\1</tt> as the placeholder for a
|
|
146
|
+
# phrase, similar to +String#sub+. Defaults to <tt>"<mark>\1</mark>"</tt>.
|
|
147
|
+
# This option is ignored if a block is specified.
|
|
148
|
+
#
|
|
149
|
+
# [+:sanitize+]
|
|
150
|
+
# Whether to sanitize +text+ before highlighting. Defaults to true.
|
|
151
|
+
#
|
|
152
|
+
# ==== Examples
|
|
116
153
|
#
|
|
117
154
|
# highlight('You searched for: rails', 'rails')
|
|
118
|
-
# # => You searched for: <mark>rails</mark>
|
|
155
|
+
# # => "You searched for: <mark>rails</mark>"
|
|
119
156
|
#
|
|
120
157
|
# highlight('You searched for: rails', /for|rails/)
|
|
121
|
-
# # => You searched <mark>for</mark>: <mark>rails</mark>
|
|
158
|
+
# # => "You searched <mark>for</mark>: <mark>rails</mark>"
|
|
122
159
|
#
|
|
123
160
|
# highlight('You searched for: ruby, rails, dhh', 'actionpack')
|
|
124
|
-
# # => You searched for: ruby, rails, dhh
|
|
161
|
+
# # => "You searched for: ruby, rails, dhh"
|
|
125
162
|
#
|
|
126
163
|
# highlight('You searched for: rails', ['for', 'rails'], highlighter: '<em>\1</em>')
|
|
127
|
-
# # => You searched <em>for</em>: <em>rails</em>
|
|
164
|
+
# # => "You searched <em>for</em>: <em>rails</em>"
|
|
128
165
|
#
|
|
129
166
|
# highlight('You searched for: rails', 'rails', highlighter: '<a href="search?q=\1">\1</a>')
|
|
130
|
-
# # => You searched for: <a href
|
|
167
|
+
# # => "You searched for: <a href=\"search?q=rails\">rails</a>"
|
|
131
168
|
#
|
|
132
|
-
# highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match
|
|
133
|
-
# # => You searched for: <a href
|
|
169
|
+
# highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match)) }
|
|
170
|
+
# # => "You searched for: <a href=\"search?q=rails\">rails</a>"
|
|
134
171
|
#
|
|
135
172
|
# highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
|
|
136
|
-
# # => <a href
|
|
173
|
+
# # => "<a href=\"javascript:alert('no!')\">ruby</a> on <mark>rails</mark>"
|
|
137
174
|
def highlight(text, phrases, options = {}, &block)
|
|
138
175
|
text = sanitize(text) if options.fetch(:sanitize, true)
|
|
139
176
|
|
|
@@ -156,30 +193,45 @@ module ActionView
|
|
|
156
193
|
end.html_safe
|
|
157
194
|
end
|
|
158
195
|
|
|
159
|
-
# Extracts
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
196
|
+
# Extracts the first occurrence of +phrase+ plus surrounding text from
|
|
197
|
+
# +text+. An omission marker is prepended / appended if the start / end of
|
|
198
|
+
# the result does not coincide with the start / end of +text+. The result
|
|
199
|
+
# is always stripped in any case. Returns +nil+ if +phrase+ isn't found.
|
|
200
|
+
#
|
|
201
|
+
# ==== Options
|
|
202
|
+
#
|
|
203
|
+
# [+:radius+]
|
|
204
|
+
# The number of characters (or tokens — see +:separator+ option) around
|
|
205
|
+
# +phrase+ to include in the result. Defaults to 100.
|
|
206
|
+
#
|
|
207
|
+
# [+:omission+]
|
|
208
|
+
# The marker to prepend / append when the start / end of the excerpt
|
|
209
|
+
# does not coincide with the start / end of +text+. Defaults to
|
|
210
|
+
# <tt>"..."</tt>.
|
|
211
|
+
#
|
|
212
|
+
# [+:separator+]
|
|
213
|
+
# The separator between tokens to count for +:radius+. Defaults to
|
|
214
|
+
# <tt>""</tt>, which treats each character as a token.
|
|
215
|
+
#
|
|
216
|
+
# ==== Examples
|
|
165
217
|
#
|
|
166
218
|
# excerpt('This is an example', 'an', radius: 5)
|
|
167
|
-
# # => ...s is an exam...
|
|
219
|
+
# # => "...s is an exam..."
|
|
168
220
|
#
|
|
169
221
|
# excerpt('This is an example', 'is', radius: 5)
|
|
170
|
-
# # => This is a...
|
|
222
|
+
# # => "This is a..."
|
|
171
223
|
#
|
|
172
224
|
# excerpt('This is an example', 'is')
|
|
173
|
-
# # => This is an example
|
|
225
|
+
# # => "This is an example"
|
|
174
226
|
#
|
|
175
227
|
# excerpt('This next thing is an example', 'ex', radius: 2)
|
|
176
|
-
# # => ...next...
|
|
228
|
+
# # => "...next..."
|
|
177
229
|
#
|
|
178
230
|
# excerpt('This is also an example', 'an', radius: 8, omission: '<chop> ')
|
|
179
|
-
# # => <chop> is also an example
|
|
231
|
+
# # => "<chop> is also an example"
|
|
180
232
|
#
|
|
181
233
|
# excerpt('This is a very beautiful morning', 'very', separator: ' ', radius: 1)
|
|
182
|
-
# # => ...a very beautiful...
|
|
234
|
+
# # => "...a very beautiful..."
|
|
183
235
|
def excerpt(text, phrase, options = {})
|
|
184
236
|
return unless text && phrase
|
|
185
237
|
|
|
@@ -215,26 +267,26 @@ module ActionView
|
|
|
215
267
|
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
|
|
216
268
|
# +plural+ is supplied, it will use that when count is > 1, otherwise
|
|
217
269
|
# it will use the Inflector to determine the plural form for the given locale,
|
|
218
|
-
# which defaults to I18n.locale
|
|
270
|
+
# which defaults to +I18n.locale+.
|
|
219
271
|
#
|
|
220
272
|
# The word will be pluralized using rules defined for the locale
|
|
221
273
|
# (you must define your own inflection rules for languages other than English).
|
|
222
274
|
# See ActiveSupport::Inflector.pluralize
|
|
223
275
|
#
|
|
224
276
|
# pluralize(1, 'person')
|
|
225
|
-
# # => 1 person
|
|
277
|
+
# # => "1 person"
|
|
226
278
|
#
|
|
227
279
|
# pluralize(2, 'person')
|
|
228
|
-
# # => 2 people
|
|
280
|
+
# # => "2 people"
|
|
229
281
|
#
|
|
230
282
|
# pluralize(3, 'person', plural: 'users')
|
|
231
|
-
# # => 3 users
|
|
283
|
+
# # => "3 users"
|
|
232
284
|
#
|
|
233
285
|
# pluralize(0, 'person')
|
|
234
|
-
# # => 0 people
|
|
286
|
+
# # => "0 people"
|
|
235
287
|
#
|
|
236
288
|
# pluralize(2, 'Person', locale: :de)
|
|
237
|
-
# # => 2 Personen
|
|
289
|
+
# # => "2 Personen"
|
|
238
290
|
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
|
|
239
291
|
word = if count == 1 || count.to_s.match?(/^1(\.0+)?$/)
|
|
240
292
|
singular
|
|
@@ -250,22 +302,24 @@ module ActionView
|
|
|
250
302
|
# (which is 80 by default).
|
|
251
303
|
#
|
|
252
304
|
# word_wrap('Once upon a time')
|
|
253
|
-
# # => Once upon a time
|
|
305
|
+
# # => "Once upon a time"
|
|
254
306
|
#
|
|
255
307
|
# word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
|
|
256
|
-
# # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined...
|
|
308
|
+
# # => "Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined..."
|
|
257
309
|
#
|
|
258
310
|
# word_wrap('Once upon a time', line_width: 8)
|
|
259
|
-
# # => Once\nupon a\ntime
|
|
311
|
+
# # => "Once\nupon a\ntime"
|
|
260
312
|
#
|
|
261
313
|
# word_wrap('Once upon a time', line_width: 1)
|
|
262
|
-
# # => Once\nupon\na\ntime
|
|
314
|
+
# # => "Once\nupon\na\ntime"
|
|
263
315
|
#
|
|
264
|
-
#
|
|
316
|
+
# You can also specify a custom +break_sequence+ ("\n" by default):
|
|
265
317
|
#
|
|
266
318
|
# word_wrap('Once upon a time', line_width: 1, break_sequence: "\r\n")
|
|
267
|
-
# # => Once\r\nupon\r\na\r\ntime
|
|
319
|
+
# # => "Once\r\nupon\r\na\r\ntime"
|
|
268
320
|
def word_wrap(text, line_width: 80, break_sequence: "\n")
|
|
321
|
+
return +"" if text.empty?
|
|
322
|
+
|
|
269
323
|
# Match up to `line_width` characters, followed by one of
|
|
270
324
|
# (1) non-newline whitespace plus an optional newline
|
|
271
325
|
# (2) the end of the string, ignoring any trailing newlines
|
|
@@ -334,7 +388,7 @@ module ActionView
|
|
|
334
388
|
end
|
|
335
389
|
end
|
|
336
390
|
|
|
337
|
-
# Creates a Cycle object whose
|
|
391
|
+
# Creates a Cycle object whose +to_s+ method cycles through elements of an
|
|
338
392
|
# array every time it is called. This can be used for example, to alternate
|
|
339
393
|
# classes for table rows. You can use named cycles to allow nesting in loops.
|
|
340
394
|
# Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
|
|
@@ -343,8 +397,8 @@ module ActionView
|
|
|
343
397
|
# and passing the name of the cycle. The current cycle string can be obtained
|
|
344
398
|
# anytime using the current_cycle method.
|
|
345
399
|
#
|
|
346
|
-
#
|
|
347
|
-
# @items = [1,2,3,4]
|
|
400
|
+
# <%# Alternate CSS classes for even and odd numbers... %>
|
|
401
|
+
# <% @items = [1,2,3,4] %>
|
|
348
402
|
# <table>
|
|
349
403
|
# <% @items.each do |item| %>
|
|
350
404
|
# <tr class="<%= cycle("odd", "even") -%>">
|
|
@@ -354,10 +408,12 @@ module ActionView
|
|
|
354
408
|
# </table>
|
|
355
409
|
#
|
|
356
410
|
#
|
|
357
|
-
#
|
|
358
|
-
# @items =
|
|
359
|
-
#
|
|
360
|
-
#
|
|
411
|
+
# <%# Cycle CSS classes for rows, and text colors for values within each row %>
|
|
412
|
+
# <% @items = [
|
|
413
|
+
# { first: "Robert", middle: "Daniel", last: "James" },
|
|
414
|
+
# { first: "Emily", middle: "Shannon", maiden: "Pike", last: "Hicks" },
|
|
415
|
+
# { first: "June", middle: "Dae", last: "Jones" },
|
|
416
|
+
# ] %>
|
|
361
417
|
# <% @items.each do |item| %>
|
|
362
418
|
# <tr class="<%= cycle("odd", "even", name: "row_class") -%>">
|
|
363
419
|
# <td>
|
|
@@ -388,8 +444,8 @@ module ActionView
|
|
|
388
444
|
# for complex table highlighting or any other design need which requires
|
|
389
445
|
# the current cycle string in more than one place.
|
|
390
446
|
#
|
|
391
|
-
#
|
|
392
|
-
# @items = [1,2,3,4]
|
|
447
|
+
# <%# Alternate background colors %>
|
|
448
|
+
# <% @items = [1,2,3,4] %>
|
|
393
449
|
# <% @items.each do |item| %>
|
|
394
450
|
# <div style="background-color:<%= cycle("red","white","blue") %>">
|
|
395
451
|
# <span style="background-color:<%= current_cycle %>"><%= item %></span>
|
|
@@ -403,8 +459,8 @@ module ActionView
|
|
|
403
459
|
# Resets a cycle so that it starts from the first element the next time
|
|
404
460
|
# it is called. Pass in +name+ to reset a named cycle.
|
|
405
461
|
#
|
|
406
|
-
#
|
|
407
|
-
# @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
|
|
462
|
+
# <%# Alternate CSS classes for even and odd numbers... %>
|
|
463
|
+
# <% @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]] %>
|
|
408
464
|
# <table>
|
|
409
465
|
# <% @items.each do |item| %>
|
|
410
466
|
# <tr class="<%= cycle("even", "odd") -%>">
|
|
@@ -195,42 +195,6 @@ module ActionView
|
|
|
195
195
|
# link_to "Visit Other Site", "https://rubyonrails.org/", data: { turbo_confirm: "Are you sure?" }
|
|
196
196
|
# # => <a href="https://rubyonrails.org/" data-turbo-confirm="Are you sure?">Visit Other Site</a>
|
|
197
197
|
#
|
|
198
|
-
# ==== Deprecated: \Rails UJS Attributes
|
|
199
|
-
#
|
|
200
|
-
# Prior to \Rails 7, \Rails shipped with a JavaScript library called <tt>@rails/ujs</tt> on by default. Following \Rails 7,
|
|
201
|
-
# this library is no longer on by default. This library integrated with the following options:
|
|
202
|
-
#
|
|
203
|
-
# * <tt>method: symbol of HTTP verb</tt> - This modifier will dynamically
|
|
204
|
-
# create an HTML form and immediately submit the form for processing using
|
|
205
|
-
# the HTTP verb specified. Useful for having links perform a POST operation
|
|
206
|
-
# in dangerous actions like deleting a record (which search bots can follow
|
|
207
|
-
# while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>.
|
|
208
|
-
# Note that if the user has JavaScript disabled, the request will fall back
|
|
209
|
-
# to using GET. If <tt>href: '#'</tt> is used and the user has JavaScript
|
|
210
|
-
# disabled clicking the link will have no effect. If you are relying on the
|
|
211
|
-
# POST behavior, you should check for it in your controller's action by using
|
|
212
|
-
# the request object's methods for <tt>post?</tt>, <tt>delete?</tt>, <tt>patch?</tt>, or <tt>put?</tt>.
|
|
213
|
-
# * <tt>remote: true</tt> - This will allow <tt>@rails/ujs</tt>
|
|
214
|
-
# to make an Ajax request to the URL in question instead of following
|
|
215
|
-
# the link.
|
|
216
|
-
#
|
|
217
|
-
# <tt>@rails/ujs</tt> also integrated with the following +:data+ options:
|
|
218
|
-
#
|
|
219
|
-
# * <tt>confirm: "question?"</tt> - This will allow <tt>@rails/ujs</tt>
|
|
220
|
-
# to prompt with the question specified (in this case, the
|
|
221
|
-
# resulting text would be <tt>question?</tt>). If the user accepts, the
|
|
222
|
-
# link is processed normally, otherwise no action is taken.
|
|
223
|
-
# * <tt>:disable_with</tt> - Value of this parameter will be used as the
|
|
224
|
-
# name for a disabled version of the link.
|
|
225
|
-
#
|
|
226
|
-
# ===== \Rails UJS Examples
|
|
227
|
-
#
|
|
228
|
-
# link_to "Remove Profile", profile_path(@profile), method: :delete
|
|
229
|
-
# # => <a href="/profiles/1" rel="nofollow" data-method="delete">Remove Profile</a>
|
|
230
|
-
#
|
|
231
|
-
# link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
|
|
232
|
-
# # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
|
|
233
|
-
#
|
|
234
198
|
def link_to(name = nil, options = nil, html_options = nil, &block)
|
|
235
199
|
html_options, options, name = options, name, block if block_given?
|
|
236
200
|
options ||= {}
|
|
@@ -256,8 +220,9 @@ module ActionView
|
|
|
256
220
|
# +:form_class+ option within +html_options+. It defaults to
|
|
257
221
|
# <tt>"button_to"</tt> to allow styling of the form and its children.
|
|
258
222
|
#
|
|
259
|
-
# The form submits a POST request by default
|
|
260
|
-
#
|
|
223
|
+
# The form submits a POST request by default if the object is not persisted;
|
|
224
|
+
# conversely, if the object is persisted, it will submit a PATCH request.
|
|
225
|
+
# To specify a different HTTP verb use the +:method+ option within +html_options+.
|
|
261
226
|
#
|
|
262
227
|
# If the HTML button generated from +button_to+ does not work with your layout, you can
|
|
263
228
|
# consider using the +link_to+ method with the +data-turbo-method+
|
|
@@ -328,32 +293,6 @@ module ActionView
|
|
|
328
293
|
# # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
|
|
329
294
|
# # </form>"
|
|
330
295
|
#
|
|
331
|
-
# ==== Deprecated: \Rails UJS Attributes
|
|
332
|
-
#
|
|
333
|
-
# Prior to \Rails 7, \Rails shipped with a JavaScript library called <tt>@rails/ujs</tt> on by default. Following \Rails 7,
|
|
334
|
-
# this library is no longer on by default. This library integrated with the following options:
|
|
335
|
-
#
|
|
336
|
-
# * <tt>:remote</tt> - If set to true, will allow <tt>@rails/ujs</tt> to control the
|
|
337
|
-
# submit behavior. By default this behavior is an Ajax submit.
|
|
338
|
-
#
|
|
339
|
-
# <tt>@rails/ujs</tt> also integrated with the following +:data+ options:
|
|
340
|
-
#
|
|
341
|
-
# * <tt>confirm: "question?"</tt> - This will allow <tt>@rails/ujs</tt>
|
|
342
|
-
# to prompt with the question specified (in this case, the
|
|
343
|
-
# resulting text would be <tt>question?</tt>). If the user accepts, the
|
|
344
|
-
# button is processed normally, otherwise no action is taken.
|
|
345
|
-
# * <tt>:disable_with</tt> - Value of this parameter will be
|
|
346
|
-
# used as the value for a disabled version of the submit
|
|
347
|
-
# button when the form is submitted.
|
|
348
|
-
#
|
|
349
|
-
# ===== \Rails UJS Examples
|
|
350
|
-
#
|
|
351
|
-
# <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
|
|
352
|
-
# # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
|
|
353
|
-
# # <button type="submit">Create</button>
|
|
354
|
-
# # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
|
|
355
|
-
# # </form>"
|
|
356
|
-
#
|
|
357
296
|
def button_to(name = nil, options = nil, html_options = nil, &block)
|
|
358
297
|
html_options, options = options, name if block_given?
|
|
359
298
|
html_options ||= {}
|
|
@@ -617,14 +556,14 @@ module ActionView
|
|
|
617
556
|
|
|
618
557
|
options ||= options_as_kwargs
|
|
619
558
|
check_parameters ||= options.is_a?(Hash) && options.delete(:check_parameters)
|
|
620
|
-
url_string = URI::
|
|
559
|
+
url_string = URI::RFC2396_PARSER.unescape(url_for(options)).force_encoding(Encoding::BINARY)
|
|
621
560
|
|
|
622
561
|
# We ignore any extra parameters in the request_uri if the
|
|
623
562
|
# submitted URL doesn't have any either. This lets the function
|
|
624
563
|
# work with things like ?order=asc
|
|
625
564
|
# the behavior can be disabled with check_parameters: true
|
|
626
565
|
request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
|
|
627
|
-
request_uri = URI::
|
|
566
|
+
request_uri = URI::RFC2396_PARSER.unescape(request_uri).force_encoding(Encoding::BINARY)
|
|
628
567
|
|
|
629
568
|
if %r{^\w+://}.match?(url_string)
|
|
630
569
|
request_uri = +"#{request.protocol}#{request.host_with_port}#{request_uri}"
|
|
@@ -636,19 +575,6 @@ module ActionView
|
|
|
636
575
|
url_string == request_uri
|
|
637
576
|
end
|
|
638
577
|
|
|
639
|
-
if RUBY_VERSION.start_with?("2.7")
|
|
640
|
-
using Module.new {
|
|
641
|
-
refine UrlHelper do
|
|
642
|
-
alias :_current_page? :current_page?
|
|
643
|
-
end
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
def current_page?(*args) # :nodoc:
|
|
647
|
-
options = args.pop
|
|
648
|
-
options.is_a?(Hash) ? _current_page?(*args, **options) : _current_page?(*args, options)
|
|
649
|
-
end
|
|
650
|
-
end
|
|
651
|
-
|
|
652
578
|
# Creates an SMS anchor link tag to the specified +phone_number+. When the
|
|
653
579
|
# link is clicked, the default SMS messaging app is opened ready to send a
|
|
654
580
|
# message to the linked phone number. If the +body+ option is specified,
|
|
@@ -784,7 +710,7 @@ module ActionView
|
|
|
784
710
|
end
|
|
785
711
|
|
|
786
712
|
def add_method_to_attributes!(html_options, method)
|
|
787
|
-
if method_not_get_method?(method) && !html_options["rel"]
|
|
713
|
+
if method_not_get_method?(method) && !html_options["rel"].to_s.include?("nofollow")
|
|
788
714
|
if html_options["rel"].blank?
|
|
789
715
|
html_options["rel"] = "nofollow"
|
|
790
716
|
else
|
data/lib/action_view/layouts.rb
CHANGED
|
@@ -152,7 +152,7 @@ module ActionView
|
|
|
152
152
|
# The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
|
|
153
153
|
# <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
|
|
154
154
|
#
|
|
155
|
-
# Setting the layout to +nil+ forces it to be looked up in the filesystem and
|
|
155
|
+
# Setting the layout to +nil+ forces it to be looked up in the filesystem and falls back to the parent behavior if none exists.
|
|
156
156
|
# Setting it to +nil+ is useful to re-enable template lookup overriding a previous configuration set in the parent:
|
|
157
157
|
#
|
|
158
158
|
# class ApplicationController < ActionController::Base
|
|
@@ -164,7 +164,7 @@ module ActionView
|
|
|
164
164
|
# end
|
|
165
165
|
#
|
|
166
166
|
# class CommentsController < ApplicationController
|
|
167
|
-
# # Will search for "comments" layout and
|
|
167
|
+
# # Will search for "comments" layout and fall back to "application" layout
|
|
168
168
|
# layout nil
|
|
169
169
|
# end
|
|
170
170
|
#
|
|
@@ -209,11 +209,9 @@ module ActionView
|
|
|
209
209
|
|
|
210
210
|
included do
|
|
211
211
|
class_attribute :_layout, instance_accessor: false
|
|
212
|
-
class_attribute :_layout_conditions, instance_accessor: false, default: {}
|
|
212
|
+
class_attribute :_layout_conditions, instance_accessor: false, instance_reader: true, default: {}
|
|
213
213
|
|
|
214
214
|
_write_layout_method
|
|
215
|
-
|
|
216
|
-
delegate :_layout_conditions, to: :class
|
|
217
215
|
end
|
|
218
216
|
|
|
219
217
|
module ClassMethods
|
|
@@ -286,7 +284,7 @@ module ActionView
|
|
|
286
284
|
silence_redefinition_of_method(:_layout)
|
|
287
285
|
|
|
288
286
|
prefixes = /\blayouts/.match?(_implied_layout_name) ? [] : ["layouts"]
|
|
289
|
-
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"
|
|
290
288
|
name_clause = if name
|
|
291
289
|
default_behavior
|
|
292
290
|
else
|
|
@@ -327,7 +325,7 @@ module ActionView
|
|
|
327
325
|
|
|
328
326
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
329
327
|
# frozen_string_literal: true
|
|
330
|
-
def _layout(lookup_context, formats)
|
|
328
|
+
def _layout(lookup_context, formats, keys)
|
|
331
329
|
if _conditional_layout?
|
|
332
330
|
#{layout_definition}
|
|
333
331
|
else
|
|
@@ -349,7 +347,7 @@ module ActionView
|
|
|
349
347
|
end
|
|
350
348
|
end
|
|
351
349
|
|
|
352
|
-
def
|
|
350
|
+
def _process_render_template_options(options) # :nodoc:
|
|
353
351
|
super
|
|
354
352
|
|
|
355
353
|
if _include_layout?(options)
|
|
@@ -391,8 +389,8 @@ module ActionView
|
|
|
391
389
|
case name
|
|
392
390
|
when String then _normalize_layout(name)
|
|
393
391
|
when Proc then name
|
|
394
|
-
when true then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, true) }
|
|
395
|
-
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) }
|
|
396
394
|
when false, nil then nil
|
|
397
395
|
else
|
|
398
396
|
raise ArgumentError,
|
|
@@ -414,9 +412,9 @@ module ActionView
|
|
|
414
412
|
#
|
|
415
413
|
# ==== Returns
|
|
416
414
|
# * <tt>template</tt> - The template object for the default layout (or +nil+)
|
|
417
|
-
def _default_layout(lookup_context, formats, require_layout = false)
|
|
415
|
+
def _default_layout(lookup_context, formats, keys, require_layout = false)
|
|
418
416
|
begin
|
|
419
|
-
value = _layout(lookup_context, formats) if action_has_layout?
|
|
417
|
+
value = _layout(lookup_context, formats, keys) if action_has_layout?
|
|
420
418
|
rescue NameError => e
|
|
421
419
|
raise e, "Could not render layout: #{e.message}"
|
|
422
420
|
end
|
|
@@ -430,7 +428,7 @@ module ActionView
|
|
|
430
428
|
end
|
|
431
429
|
|
|
432
430
|
def _include_layout?(options)
|
|
433
|
-
|
|
431
|
+
!options.keys.intersect?([:body, :plain, :html, :inline, :partial]) || options.key?(:layout)
|
|
434
432
|
end
|
|
435
433
|
end
|
|
436
434
|
end
|
|
@@ -18,7 +18,7 @@ module ActionView
|
|
|
18
18
|
info do
|
|
19
19
|
message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
|
|
20
20
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
|
21
|
-
message << " (Duration: #{event.duration.round(1)}ms |
|
|
21
|
+
message << " (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
subscribe_log_level :render_template, :debug
|
|
@@ -27,7 +27,7 @@ module ActionView
|
|
|
27
27
|
debug do
|
|
28
28
|
message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
|
|
29
29
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
|
30
|
-
message << " (Duration: #{event.duration.round(1)}ms |
|
|
30
|
+
message << " (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
|
31
31
|
message << " #{cache_message(event.payload)}" unless event.payload[:cache_hit].nil?
|
|
32
32
|
message
|
|
33
33
|
end
|
|
@@ -37,7 +37,7 @@ module ActionView
|
|
|
37
37
|
def render_layout(event)
|
|
38
38
|
info do
|
|
39
39
|
message = +" Rendered layout #{from_rails_root(event.payload[:identifier])}"
|
|
40
|
-
message << " (Duration: #{event.duration.round(1)}ms |
|
|
40
|
+
message << " (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
subscribe_log_level :render_layout, :info
|
|
@@ -48,7 +48,7 @@ module ActionView
|
|
|
48
48
|
debug do
|
|
49
49
|
message = +" Rendered collection of #{from_rails_root(identifier)}"
|
|
50
50
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
|
51
|
-
message << " #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms |
|
|
51
|
+
message << " #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
|
52
52
|
message
|
|
53
53
|
end
|
|
54
54
|
end
|
|
@@ -96,6 +96,10 @@ module ActionView
|
|
|
96
96
|
|
|
97
97
|
def finish(name, id, payload)
|
|
98
98
|
end
|
|
99
|
+
|
|
100
|
+
def silenced?(_)
|
|
101
|
+
logger.nil? || !logger.debug?
|
|
102
|
+
end
|
|
99
103
|
end
|
|
100
104
|
|
|
101
105
|
def self.attach_to(*)
|
data/lib/action_view/railtie.rb
CHANGED
|
@@ -116,7 +116,6 @@ module ActionView
|
|
|
116
116
|
view_reloader = ActionView::CacheExpiry::ViewReloader.new(watcher: app.config.file_watcher)
|
|
117
117
|
|
|
118
118
|
app.reloaders << view_reloader
|
|
119
|
-
view_reloader.execute
|
|
120
119
|
app.reloader.to_run do
|
|
121
120
|
require_unload_lock!
|
|
122
121
|
view_reloader.execute
|