actionview 6.1.6.1 → 7.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -347
  3. data/MIT-LICENSE +2 -1
  4. data/lib/action_view/base.rb +3 -3
  5. data/lib/action_view/buffers.rb +2 -2
  6. data/lib/action_view/cache_expiry.rb +46 -32
  7. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  8. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  9. data/lib/action_view/dependency_tracker.rb +6 -147
  10. data/lib/action_view/digestor.rb +7 -4
  11. data/lib/action_view/flows.rb +4 -4
  12. data/lib/action_view/gem_version.rb +4 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  14. data/lib/action_view/helpers/asset_tag_helper.rb +84 -29
  15. data/lib/action_view/helpers/asset_url_helper.rb +7 -7
  16. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  17. data/lib/action_view/helpers/cache_helper.rb +51 -3
  18. data/lib/action_view/helpers/capture_helper.rb +2 -2
  19. data/lib/action_view/helpers/controller_helper.rb +2 -2
  20. data/lib/action_view/helpers/csp_helper.rb +1 -1
  21. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  22. data/lib/action_view/helpers/date_helper.rb +6 -7
  23. data/lib/action_view/helpers/debug_helper.rb +3 -1
  24. data/lib/action_view/helpers/form_helper.rb +72 -12
  25. data/lib/action_view/helpers/form_options_helper.rb +65 -33
  26. data/lib/action_view/helpers/form_tag_helper.rb +75 -32
  27. data/lib/action_view/helpers/javascript_helper.rb +3 -5
  28. data/lib/action_view/helpers/number_helper.rb +3 -4
  29. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  30. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  31. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  32. data/lib/action_view/helpers/tag_helper.rb +25 -44
  33. data/lib/action_view/helpers/tags/base.rb +3 -15
  34. data/lib/action_view/helpers/tags/check_box.rb +2 -2
  35. data/lib/action_view/helpers/tags/collection_select.rb +1 -1
  36. data/lib/action_view/helpers/tags/hidden_field.rb +0 -4
  37. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  38. data/lib/action_view/helpers/tags/weekday_select.rb +27 -0
  39. data/lib/action_view/helpers/tags.rb +3 -2
  40. data/lib/action_view/helpers/text_helper.rb +24 -13
  41. data/lib/action_view/helpers/translation_helper.rb +1 -2
  42. data/lib/action_view/helpers/url_helper.rb +102 -77
  43. data/lib/action_view/helpers.rb +25 -25
  44. data/lib/action_view/lookup_context.rb +33 -52
  45. data/lib/action_view/model_naming.rb +1 -1
  46. data/lib/action_view/path_set.rb +16 -22
  47. data/lib/action_view/railtie.rb +14 -1
  48. data/lib/action_view/render_parser.rb +188 -0
  49. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  50. data/lib/action_view/renderer/partial_renderer.rb +0 -34
  51. data/lib/action_view/renderer/renderer.rb +4 -4
  52. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
  53. data/lib/action_view/renderer/template_renderer.rb +6 -2
  54. data/lib/action_view/rendering.rb +2 -2
  55. data/lib/action_view/ripper_ast_parser.rb +198 -0
  56. data/lib/action_view/routing_url_for.rb +1 -1
  57. data/lib/action_view/template/error.rb +108 -13
  58. data/lib/action_view/template/handlers/erb.rb +6 -0
  59. data/lib/action_view/template/handlers.rb +3 -3
  60. data/lib/action_view/template/html.rb +3 -3
  61. data/lib/action_view/template/inline.rb +3 -3
  62. data/lib/action_view/template/raw_file.rb +3 -3
  63. data/lib/action_view/template/resolver.rb +84 -311
  64. data/lib/action_view/template/text.rb +3 -3
  65. data/lib/action_view/template/types.rb +14 -12
  66. data/lib/action_view/template.rb +10 -1
  67. data/lib/action_view/template_details.rb +66 -0
  68. data/lib/action_view/template_path.rb +64 -0
  69. data/lib/action_view/test_case.rb +6 -2
  70. data/lib/action_view/testing/resolvers.rb +11 -12
  71. data/lib/action_view/unbound_template.rb +33 -7
  72. data/lib/action_view.rb +3 -4
  73. metadata +25 -19
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_view/helpers/javascript_helper"
4
3
  require "active_support/core_ext/array/access"
5
4
  require "active_support/core_ext/hash/keys"
6
5
  require "active_support/core_ext/string/output_safety"
6
+ require "action_view/helpers/tag_helper"
7
7
 
8
8
  module ActionView
9
9
  # = Action View URL Helpers
10
- module Helpers #:nodoc:
10
+ module Helpers # :nodoc:
11
11
  # Provides a set of methods for making links and getting URLs that
12
12
  # depend on the routing subsystem (see ActionDispatch::Routing).
13
13
  # This allows you to use the same format for links in views
@@ -29,6 +29,8 @@ module ActionView
29
29
  end
30
30
  end
31
31
 
32
+ mattr_accessor :button_to_generates_button_tag, default: false
33
+
32
34
  # Basic implementation of url_for to allow use helpers without routes existence
33
35
  def url_for(options = nil) # :nodoc:
34
36
  case options
@@ -101,17 +103,8 @@ module ActionView
101
103
  # completion of the Ajax request and performing JavaScript operations once
102
104
  # they're complete
103
105
  #
104
- # ==== Data attributes
105
- #
106
- # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
107
- # driver to prompt with the question specified (in this case, the
108
- # resulting text would be <tt>question?</tt>. If the user accepts, the
109
- # link is processed normally, otherwise no action is taken.
110
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the
111
- # name for a disabled version of the link. This feature is provided by
112
- # the unobtrusive JavaScript driver.
113
- #
114
106
  # ==== Examples
107
+ #
115
108
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
116
109
  # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
117
110
  # your application on resources and use
@@ -184,15 +177,27 @@ module ActionView
184
177
  # link_to("Destroy", "http://www.example.com", method: :delete)
185
178
  # # => <a href='http://www.example.com' rel="nofollow" data-method="delete">Destroy</a>
186
179
  #
187
- # You can also use custom data attributes using the <tt>:data</tt> option:
188
- #
189
- # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
190
- # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
191
- #
192
180
  # Also you can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
193
181
  #
194
182
  # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
195
183
  # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
184
+ #
185
+ # ==== Deprecated: Rails UJS attributes
186
+ #
187
+ # Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
188
+ # this library is no longer on by default. This library integrated with the following options:
189
+ #
190
+ # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
191
+ # driver to prompt with the question specified (in this case, the
192
+ # resulting text would be <tt>question?</tt>. If the user accepts, the
193
+ # link is processed normally, otherwise no action is taken.
194
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the
195
+ # name for a disabled version of the link. This feature is provided by
196
+ # the unobtrusive JavaScript driver.
197
+ #
198
+ # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
199
+ # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
200
+ #
196
201
  def link_to(name = nil, options = nil, html_options = nil, &block)
197
202
  html_options, options, name = options, name, block if block_given?
198
203
  options ||= {}
@@ -212,20 +217,24 @@ module ActionView
212
217
  # using the +link_to+ method with the <tt>:method</tt> modifier as described in
213
218
  # the +link_to+ documentation.
214
219
  #
215
- # By default, the generated form element has a class name of <tt>button_to</tt>
216
- # to allow styling of the form itself and its children. This can be changed
217
- # using the <tt>:form_class</tt> modifier within +html_options+. You can control
218
- # the form submission and input element behavior using +html_options+.
219
- # This method accepts the <tt>:method</tt> modifier described in the +link_to+ documentation.
220
- # If no <tt>:method</tt> modifier is given, it will default to performing a POST operation.
221
- # You can also disable the button by passing <tt>disabled: true</tt> in +html_options+.
222
- # If you are using RESTful routes, you can pass the <tt>:method</tt>
223
- # to change the HTTP verb used to submit the form.
220
+ # You can control the form and button behavior with +html_options+. Most
221
+ # values in +html_options+ are passed through to the button element. For
222
+ # example, passing a +:class+ option within +html_options+ will set the
223
+ # class attribute of the button element.
224
+ #
225
+ # The class attribute of the form element can be set by passing a
226
+ # +:form_class+ option within +html_options+. It defaults to
227
+ # <tt>"button_to"</tt> to allow styling of the form and its children.
228
+ #
229
+ # The form submits a POST request by default. You can specify a different
230
+ # HTTP verb via the +:method+ option within +html_options+.
224
231
  #
225
232
  # ==== Options
226
233
  # The +options+ hash accepts the same options as +url_for+.
227
234
  #
228
- # There are a few special +html_options+:
235
+ # Most values in +html_options+ are passed through to the button element,
236
+ # but there are a few special options:
237
+ #
229
238
  # * <tt>:method</tt> - \Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
230
239
  # <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
231
240
  # * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
@@ -250,12 +259,21 @@ module ActionView
250
259
  # ==== Examples
251
260
  # <%= button_to "New", action: "new" %>
252
261
  # # => "<form method="post" action="/controller/new" class="button_to">
253
- # # <input value="New" type="submit" />
262
+ # # <button type="submit">New</button>
263
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
254
264
  # # </form>"
255
265
  #
256
266
  # <%= button_to "New", new_article_path %>
257
267
  # # => "<form method="post" action="/articles/new" class="button_to">
258
- # # <input value="New" type="submit" />
268
+ # # <button type="submit">New</button>
269
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
270
+ # # </form>"
271
+ #
272
+ # <%= button_to "New", new_article_path, params: { time: Time.now } %>
273
+ # # => "<form method="post" action="/articles/new" class="button_to">
274
+ # # <button type="submit">New</button>
275
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
276
+ # # <input type="hidden" name="time" value="2021-04-08 14:06:09 -0500">
259
277
  # # </form>"
260
278
  #
261
279
  # <%= button_to [:make_happy, @user] do %>
@@ -265,35 +283,34 @@ module ActionView
265
283
  # # <button type="submit">
266
284
  # # Make happy <strong><%= @user.name %></strong>
267
285
  # # </button>
286
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
268
287
  # # </form>"
269
288
  #
270
289
  # <%= button_to "New", { action: "new" }, form_class: "new-thing" %>
271
290
  # # => "<form method="post" action="/controller/new" class="new-thing">
272
- # # <input value="New" type="submit" />
291
+ # # <button type="submit">New</button>
292
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
273
293
  # # </form>"
274
294
  #
275
- #
276
295
  # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
277
296
  # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
278
- # # <input value="Create" type="submit" />
297
+ # # <button type="submit">Create</button>
279
298
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
280
299
  # # </form>"
281
300
  #
282
- #
283
301
  # <%= button_to "Delete Image", { action: "delete", id: @image.id },
284
302
  # method: :delete, data: { confirm: "Are you sure?" } %>
285
303
  # # => "<form method="post" action="/images/delete/1" class="button_to">
286
304
  # # <input type="hidden" name="_method" value="delete" />
287
- # # <input data-confirm='Are you sure?' value="Delete Image" type="submit" />
305
+ # # <button data-confirm='Are you sure?' type="submit">Delete Image</button>
288
306
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
289
307
  # # </form>"
290
308
  #
291
- #
292
309
  # <%= button_to('Destroy', 'http://www.example.com',
293
310
  # method: :delete, remote: true, data: { confirm: 'Are you sure?', disable_with: 'loading...' }) %>
294
311
  # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
295
312
  # # <input name='_method' value='delete' type='hidden' />
296
- # # <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
313
+ # # <button type='submit' data-disable-with='loading...' data-confirm='Are you sure?'>Destroy</button>
297
314
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
298
315
  # # </form>"
299
316
  # #
@@ -327,8 +344,8 @@ module ActionView
327
344
  html_options = convert_options_to_data_attributes(options, html_options)
328
345
  html_options["type"] = "submit"
329
346
 
330
- button = if block_given?
331
- content_tag("button", html_options, &block)
347
+ button = if block_given? || button_to_generates_button_tag
348
+ content_tag("button", name || url, html_options, &block)
332
349
  else
333
350
  html_options["value"] = name || url
334
351
  tag("input", html_options)
@@ -337,8 +354,7 @@ module ActionView
337
354
  inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
338
355
  if params
339
356
  to_form_params(params).each do |param|
340
- inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value],
341
- autocomplete: "off")
357
+ inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value])
342
358
  end
343
359
  end
344
360
  content_tag("form", inner_tags, form_options)
@@ -467,9 +483,9 @@ module ActionView
467
483
  # mail_to "me@domain.com", "My email"
468
484
  # # => <a href="mailto:me@domain.com">My email</a>
469
485
  #
470
- # mail_to "me@domain.com", "My email", cc: "ccaddress@domain.com",
486
+ # mail_to "me@domain.com", cc: "ccaddress@domain.com",
471
487
  # subject: "This is an example email"
472
- # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
488
+ # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">me@domain.com</a>
473
489
  #
474
490
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
475
491
  #
@@ -480,7 +496,7 @@ module ActionView
480
496
  # <strong>Email me:</strong> <span>me@domain.com</span>
481
497
  # </a>
482
498
  def mail_to(email_address, name = nil, html_options = {}, &block)
483
- html_options, name = name, nil if block_given?
499
+ html_options, name = name, nil if name.is_a?(Hash)
484
500
  html_options = (html_options || {}).stringify_keys
485
501
 
486
502
  extras = %w{ cc bcc body subject reply_to }.map! { |item|
@@ -583,29 +599,37 @@ module ActionView
583
599
  end
584
600
  end
585
601
 
586
- # Creates an SMS anchor link tag to the specified +phone_number+, which is
587
- # also used as the name of the link unless +name+ is specified. Additional
588
- # HTML attributes for the link can be passed in +html_options+.
602
+ # Creates an SMS anchor link tag to the specified +phone_number+. When the
603
+ # link is clicked, the default SMS messaging app is opened ready to send a
604
+ # message to the linked phone number. If the +body+ option is specified,
605
+ # the contents of the message will be preset to +body+.
589
606
  #
590
- # When clicked, an SMS message is prepopulated with the passed phone number
591
- # and optional +body+ value.
607
+ # If +name+ is not specified, +phone_number+ will be used as the name of
608
+ # the link.
592
609
  #
593
- # +sms_to+ has a +body+ option for customizing the SMS message itself by
594
- # passing special keys to +html_options+.
610
+ # A +country_code+ option is supported, which prepends a plus sign and the
611
+ # given country code to the linked phone number. For example,
612
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
613
+ # phone number.
614
+ #
615
+ # Additional HTML attributes for the link can be passed via +html_options+.
595
616
  #
596
617
  # ==== Options
618
+ # * <tt>:country_code</tt> - Prepend the country code to the phone number.
597
619
  # * <tt>:body</tt> - Preset the body of the message.
598
620
  #
599
621
  # ==== Examples
600
622
  # sms_to "5155555785"
601
623
  # # => <a href="sms:5155555785;">5155555785</a>
602
624
  #
625
+ # sms_to "5155555785", country_code: "01"
626
+ # # => <a href="sms:+015155555785;">5155555785</a>
627
+ #
603
628
  # sms_to "5155555785", "Text me"
604
629
  # # => <a href="sms:5155555785;">Text me</a>
605
630
  #
606
- # sms_to "5155555785", "Text me",
607
- # body: "Hello Jim I have a question about your product."
608
- # # => <a href="sms:5155555785;?body=Hello%20Jim%20I%20have%20a%20question%20about%20your%20product">Text me</a>
631
+ # sms_to "5155555785", body: "I have a question about your product."
632
+ # # => <a href="sms:5155555785;?body=I%20have%20a%20question%20about%20your%20product">5155555785</a>
609
633
  #
610
634
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
611
635
  #
@@ -616,46 +640,47 @@ module ActionView
616
640
  # <strong>Text me:</strong>
617
641
  # </a>
618
642
  def sms_to(phone_number, name = nil, html_options = {}, &block)
619
- html_options, name = name, nil if block_given?
643
+ html_options, name = name, nil if name.is_a?(Hash)
620
644
  html_options = (html_options || {}).stringify_keys
621
645
 
622
- extras = %w{ body }.map! { |item|
623
- option = html_options.delete(item).presence || next
624
- "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
625
- }.compact
626
- extras = extras.empty? ? "" : "?&" + extras.join("&")
646
+ country_code = html_options.delete("country_code").presence
647
+ country_code = country_code ? "+#{ERB::Util.url_encode(country_code)}" : ""
648
+
649
+ body = html_options.delete("body").presence
650
+ body = body ? "?&body=#{ERB::Util.url_encode(body)}" : ""
627
651
 
628
652
  encoded_phone_number = ERB::Util.url_encode(phone_number)
629
- html_options["href"] = "sms:#{encoded_phone_number};#{extras}"
653
+ html_options["href"] = "sms:#{country_code}#{encoded_phone_number};#{body}"
630
654
 
631
655
  content_tag("a", name || phone_number, html_options, &block)
632
656
  end
633
657
 
634
- # Creates a TEL anchor link tag to the specified +phone_number+, which is
635
- # also used as the name of the link unless +name+ is specified. Additional
636
- # HTML attributes for the link can be passed in +html_options+.
658
+ # Creates a TEL anchor link tag to the specified +phone_number+. When the
659
+ # link is clicked, the default app to make phone calls is opened and
660
+ # prepopulated with the phone number.
661
+ #
662
+ # If +name+ is not specified, +phone_number+ will be used as the name of
663
+ # the link.
637
664
  #
638
- # When clicked, the default app to make calls is opened, and it
639
- # is prepopulated with the passed phone number and optional
640
- # +country_code+ value.
665
+ # A +country_code+ option is supported, which prepends a plus sign and the
666
+ # given country code to the linked phone number. For example,
667
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
668
+ # phone number.
641
669
  #
642
- # +phone_to+ has an optional +country_code+ option which automatically adds the country
643
- # code as well as the + sign in the phone numer that gets prepopulated,
644
- # for example if +country_code: "01"+ +\+01+ will be prepended to the
645
- # phone numer, by passing special keys to +html_options+.
670
+ # Additional HTML attributes for the link can be passed via +html_options+.
646
671
  #
647
672
  # ==== Options
648
- # * <tt>:country_code</tt> - Prepends the country code to the number
673
+ # * <tt>:country_code</tt> - Prepends the country code to the phone number
649
674
  #
650
675
  # ==== Examples
651
676
  # phone_to "1234567890"
652
677
  # # => <a href="tel:1234567890">1234567890</a>
653
678
  #
654
679
  # phone_to "1234567890", "Phone me"
655
- # # => <a href="tel:134567890">Phone me</a>
680
+ # # => <a href="tel:1234567890">Phone me</a>
656
681
  #
657
- # phone_to "1234567890", "Phone me", country_code: "01"
658
- # # => <a href="tel:+015155555785">Phone me</a>
682
+ # phone_to "1234567890", country_code: "01"
683
+ # # => <a href="tel:+011234567890">1234567890</a>
659
684
  #
660
685
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
661
686
  #
@@ -666,7 +691,7 @@ module ActionView
666
691
  # <strong>Phone me:</strong>
667
692
  # </a>
668
693
  def phone_to(phone_number, name = nil, html_options = {}, &block)
669
- html_options, name = name, nil if block_given?
694
+ html_options, name = name, nil if name.is_a?(Hash)
670
695
  html_options = (html_options || {}).stringify_keys
671
696
 
672
697
  country_code = html_options.delete("country_code").presence
@@ -727,14 +752,14 @@ module ActionView
727
752
  def token_tag(token = nil, form_options: {})
728
753
  if token != false && defined?(protect_against_forgery?) && protect_against_forgery?
729
754
  token ||= form_authenticity_token(form_options: form_options)
730
- tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token, autocomplete: "off")
755
+ tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
731
756
  else
732
757
  ""
733
758
  end
734
759
  end
735
760
 
736
761
  def method_tag(method)
737
- tag("input", type: "hidden", name: "_method", value: method.to_s, autocomplete: "off")
762
+ tag("input", type: "hidden", name: "_method", value: method.to_s)
738
763
  end
739
764
 
740
765
  # Returns an array of hashes each containing :name and :value keys
@@ -1,34 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/benchmarkable"
4
+ require "action_view/helpers/capture_helper"
5
+ require "action_view/helpers/output_safety_helper"
6
+ require "action_view/helpers/tag_helper"
7
+ require "action_view/helpers/url_helper"
8
+ require "action_view/helpers/sanitize_helper"
9
+ require "action_view/helpers/text_helper"
10
+ require "action_view/helpers/active_model_helper"
11
+ require "action_view/helpers/asset_tag_helper"
12
+ require "action_view/helpers/asset_url_helper"
13
+ require "action_view/helpers/atom_feed_helper"
14
+ require "action_view/helpers/cache_helper"
15
+ require "action_view/helpers/controller_helper"
16
+ require "action_view/helpers/csp_helper"
17
+ require "action_view/helpers/csrf_helper"
18
+ require "action_view/helpers/date_helper"
19
+ require "action_view/helpers/debug_helper"
20
+ require "action_view/helpers/form_tag_helper"
21
+ require "action_view/helpers/form_helper"
22
+ require "action_view/helpers/form_options_helper"
23
+ require "action_view/helpers/javascript_helper"
24
+ require "action_view/helpers/number_helper"
25
+ require "action_view/helpers/rendering_helper"
26
+ require "action_view/helpers/translation_helper"
4
27
 
5
- module ActionView #:nodoc:
6
- module Helpers #:nodoc:
28
+ module ActionView # :nodoc:
29
+ module Helpers # :nodoc:
7
30
  extend ActiveSupport::Autoload
8
31
 
9
- autoload :ActiveModelHelper
10
- autoload :AssetTagHelper
11
- autoload :AssetUrlHelper
12
- autoload :AtomFeedHelper
13
- autoload :CacheHelper
14
- autoload :CaptureHelper
15
- autoload :ControllerHelper
16
- autoload :CspHelper
17
- autoload :CsrfHelper
18
- autoload :DateHelper
19
- autoload :DebugHelper
20
- autoload :FormHelper
21
- autoload :FormOptionsHelper
22
- autoload :FormTagHelper
23
- autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
24
- autoload :NumberHelper
25
- autoload :OutputSafetyHelper
26
- autoload :RenderingHelper
27
- autoload :SanitizeHelper
28
- autoload :TagHelper
29
- autoload :TextHelper
30
- autoload :TranslationHelper
31
- autoload :UrlHelper
32
32
  autoload :Tags
33
33
 
34
34
  def self.eager_load!
@@ -12,12 +12,11 @@ module ActionView
12
12
  # <tt>LookupContext</tt> is also responsible for generating a key, given to
13
13
  # view paths, used in the resolver cache lookup. Since this key is generated
14
14
  # only once during the request, it speeds up all cache accesses.
15
- class LookupContext #:nodoc:
15
+ class LookupContext # :nodoc:
16
16
  attr_accessor :prefixes, :rendered_format
17
17
 
18
- mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
19
-
20
- mattr_accessor :registered_details, default: []
18
+ singleton_class.attr_accessor :registered_details
19
+ self.registered_details = []
21
20
 
22
21
  def self.register_detail(name, &block)
23
22
  registered_details << name
@@ -37,7 +36,7 @@ module ActionView
37
36
  end
38
37
 
39
38
  # Holds accessors for the registered details.
40
- module Accessors #:nodoc:
39
+ module Accessors # :nodoc:
41
40
  DEFAULT_PROCS = {}
42
41
  end
43
42
 
@@ -52,7 +51,7 @@ module ActionView
52
51
  register_detail(:variants) { [] }
53
52
  register_detail(:handlers) { Template::Handlers.extensions }
54
53
 
55
- class DetailsKey #:nodoc:
54
+ class DetailsKey # :nodoc:
56
55
  alias :eql? :equal?
57
56
 
58
57
  @details_keys = Concurrent::Map.new
@@ -68,14 +67,13 @@ module ActionView
68
67
  details = details.dup
69
68
  details[:formats] &= Template::Types.symbols
70
69
  end
71
- @details_keys[details] ||= Object.new
70
+ @details_keys[details] ||= TemplateDetails::Requested.new(**details)
72
71
  end
73
72
 
74
73
  def self.clear
75
74
  ActionView::ViewPaths.all_view_paths.each do |path_set|
76
75
  path_set.each(&:clear_cache)
77
76
  end
78
- ActionView::LookupContext.fallbacks.each(&:clear_cache)
79
77
  @view_context_class = nil
80
78
  @details_keys.clear
81
79
  @digest_cache.clear
@@ -98,7 +96,7 @@ module ActionView
98
96
 
99
97
  # Calculate the details key. Remove the handlers from calculation to improve performance
100
98
  # since the user cannot modify it explicitly.
101
- def details_key #:nodoc:
99
+ def details_key # :nodoc:
102
100
  @details_key ||= DetailsKey.details_cache_key(@details) if @cache
103
101
  end
104
102
 
@@ -124,39 +122,32 @@ module ActionView
124
122
  attr_reader :view_paths, :html_fallback_for_js
125
123
 
126
124
  def find(name, prefixes = [], partial = false, keys = [], options = {})
127
- @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
125
+ name, prefixes = normalize_name(name, prefixes)
126
+ details, details_key = detail_args_for(options)
127
+ @view_paths.find(name, prefixes, partial, details, details_key, keys)
128
128
  end
129
129
  alias :find_template :find
130
130
 
131
131
  def find_all(name, prefixes = [], partial = false, keys = [], options = {})
132
- @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
132
+ name, prefixes = normalize_name(name, prefixes)
133
+ details, details_key = detail_args_for(options)
134
+ @view_paths.find_all(name, prefixes, partial, details, details_key, keys)
133
135
  end
134
136
 
135
137
  def exists?(name, prefixes = [], partial = false, keys = [], **options)
136
- @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
138
+ name, prefixes = normalize_name(name, prefixes)
139
+ details, details_key = detail_args_for(options)
140
+ @view_paths.exists?(name, prefixes, partial, details, details_key, keys)
137
141
  end
138
142
  alias :template_exists? :exists?
139
143
 
140
144
  def any?(name, prefixes = [], partial = false)
141
- @view_paths.exists?(*args_for_any(name, prefixes, partial))
145
+ name, prefixes = normalize_name(name, prefixes)
146
+ details, details_key = detail_args_for_any
147
+ @view_paths.exists?(name, prefixes, partial, details, details_key, [])
142
148
  end
143
149
  alias :any_templates? :any?
144
150
 
145
- # Adds fallbacks to the view paths. Useful in cases when you are rendering
146
- # a :file.
147
- def with_fallbacks
148
- view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
149
-
150
- if block_given?
151
- raise ArgumentError, <<~eowarn.squish
152
- Calling `with_fallbacks` with a block is not supported. Call methods on
153
- the lookup context returned by `with_fallbacks` instead.
154
- eowarn
155
- else
156
- ActionView::LookupContext.new(view_paths, @details, @prefixes)
157
- end
158
- end
159
-
160
151
  private
161
152
  # Whenever setting view paths, makes a copy so that we can manipulate them in
162
153
  # instance objects as we wish.
@@ -164,12 +155,6 @@ module ActionView
164
155
  ActionView::PathSet.new(Array(paths))
165
156
  end
166
157
 
167
- def args_for_lookup(name, prefixes, partial, keys, details_options)
168
- name, prefixes = normalize_name(name, prefixes)
169
- details, details_key = detail_args_for(details_options)
170
- [name, prefixes, partial || false, details, details_key, keys]
171
- end
172
-
173
158
  # Compute details hash and key according to user options (e.g. passed from #render).
174
159
  def detail_args_for(options) # :doc:
175
160
  return @details, details_key if options.empty? # most common path.
@@ -184,17 +169,11 @@ module ActionView
184
169
  [user_details, details_key]
185
170
  end
186
171
 
187
- def args_for_any(name, prefixes, partial)
188
- name, prefixes = normalize_name(name, prefixes)
189
- details, details_key = detail_args_for_any
190
- [name, prefixes, partial || false, details, details_key]
191
- end
192
-
193
172
  def detail_args_for_any
194
173
  @detail_args_for_any ||= begin
195
174
  details = {}
196
175
 
197
- registered_details.each do |k|
176
+ LookupContext.registered_details.each do |k|
198
177
  if k == :variants
199
178
  details[k] = :any
200
179
  else
@@ -210,19 +189,21 @@ module ActionView
210
189
  end
211
190
  end
212
191
 
213
- # Support legacy foo.erb names even though we now ignore .erb
214
- # as well as incorrectly putting part of the path in the template
215
- # name instead of the prefix.
192
+ # Fix when prefix is specified as part of the template name
216
193
  def normalize_name(name, prefixes)
217
- prefixes = prefixes.presence
218
- parts = name.to_s.split("/")
219
- parts.shift if parts.first.empty?
220
- name = parts.pop
194
+ name = name.to_s
195
+ idx = name.rindex("/")
196
+ return name, prefixes.presence || [""] unless idx
221
197
 
222
- return name, prefixes || [""] if parts.empty?
198
+ path_prefix = name[0, idx]
199
+ path_prefix = path_prefix.from(1) if path_prefix.start_with?("/")
200
+ name = name.from(idx + 1)
223
201
 
224
- parts = parts.join("/")
225
- prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
202
+ if !prefixes || prefixes.empty?
203
+ prefixes = [path_prefix]
204
+ else
205
+ prefixes = prefixes.map { |p| "#{p}/#{path_prefix}" }
206
+ end
226
207
 
227
208
  return name, prefixes
228
209
  end
@@ -254,7 +235,7 @@ module ActionView
254
235
  end
255
236
 
256
237
  def initialize_details(target, details)
257
- registered_details.each do |k|
238
+ LookupContext.registered_details.each do |k|
258
239
  target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
259
240
  end
260
241
  target
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- module ModelNaming #:nodoc:
4
+ module ModelNaming # :nodoc:
5
5
  # Converts the given object to an ActiveModel compliant one.
6
6
  def convert_to_model(object)
7
7
  object.respond_to?(:to_model) ? object.to_model : object