actionview 6.1.4.1 → 7.0.0.rc2

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 +189 -248
  3. data/MIT-LICENSE +1 -1
  4. data/lib/action_view/base.rb +4 -7
  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 +2 -2
  14. data/lib/action_view/helpers/asset_tag_helper.rb +84 -29
  15. data/lib/action_view/helpers/asset_url_helper.rb +9 -9
  16. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  17. data/lib/action_view/helpers/cache_helper.rb +52 -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 +62 -7
  23. data/lib/action_view/helpers/debug_helper.rb +3 -1
  24. data/lib/action_view/helpers/form_helper.rb +190 -75
  25. data/lib/action_view/helpers/form_options_helper.rb +68 -33
  26. data/lib/action_view/helpers/form_tag_helper.rb +126 -36
  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 +34 -6
  33. data/lib/action_view/helpers/tags/base.rb +4 -24
  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 +4 -0
  37. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  38. data/lib/action_view/helpers/tags/weekday_select.rb +28 -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 +10 -41
  42. data/lib/action_view/helpers/url_helper.rb +166 -91
  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 +2 -2
  46. data/lib/action_view/path_set.rb +16 -22
  47. data/lib/action_view/railtie.rb +19 -7
  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 +18 -2
  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 +22 -14
@@ -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
@@ -83,6 +85,8 @@ module ActionView
83
85
  # # name
84
86
  # end
85
87
  #
88
+ # link_to(active_record_model)
89
+ #
86
90
  # ==== Options
87
91
  # * <tt>:data</tt> - This option can be used to add custom data attributes.
88
92
  # * <tt>method: symbol of HTTP verb</tt> - This modifier will dynamically
@@ -101,17 +105,8 @@ module ActionView
101
105
  # completion of the Ajax request and performing JavaScript operations once
102
106
  # they're complete
103
107
  #
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
108
  # ==== Examples
109
+ #
115
110
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
116
111
  # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
117
112
  # your application on resources and use
@@ -144,6 +139,12 @@ module ActionView
144
139
  # link_to nil, "http://example.com"
145
140
  # # => <a href="http://www.example.com">http://www.example.com</a>
146
141
  #
142
+ # More concise yet, when +name+ is an Active Record model that defines a
143
+ # +to_s+ method returning a default value or a model instance attribute
144
+ #
145
+ # link_to @profile
146
+ # # => <a href="http://www.example.com/profiles/1">Eileen</a>
147
+ #
147
148
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
148
149
  #
149
150
  # <%= link_to(@profile) do %>
@@ -184,22 +185,34 @@ module ActionView
184
185
  # link_to("Destroy", "http://www.example.com", method: :delete)
185
186
  # # => <a href='http://www.example.com' rel="nofollow" data-method="delete">Destroy</a>
186
187
  #
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
188
  # Also you can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
193
189
  #
194
190
  # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
195
191
  # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
192
+ #
193
+ # ==== Deprecated: Rails UJS attributes
194
+ #
195
+ # Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
196
+ # this library is no longer on by default. This library integrated with the following options:
197
+ #
198
+ # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
199
+ # driver to prompt with the question specified (in this case, the
200
+ # resulting text would be <tt>question?</tt>. If the user accepts, the
201
+ # link is processed normally, otherwise no action is taken.
202
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the
203
+ # name for a disabled version of the link. This feature is provided by
204
+ # the unobtrusive JavaScript driver.
205
+ #
206
+ # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
207
+ # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
208
+ #
196
209
  def link_to(name = nil, options = nil, html_options = nil, &block)
197
210
  html_options, options, name = options, name, block if block_given?
198
211
  options ||= {}
199
212
 
200
213
  html_options = convert_options_to_data_attributes(options, html_options)
201
214
 
202
- url = url_for(options)
215
+ url = url_target(name, options)
203
216
  html_options["href"] ||= url
204
217
 
205
218
  content_tag("a", name || url, html_options, &block)
@@ -212,20 +225,32 @@ module ActionView
212
225
  # using the +link_to+ method with the <tt>:method</tt> modifier as described in
213
226
  # the +link_to+ documentation.
214
227
  #
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.
228
+ # You can control the form and button behavior with +html_options+. Most
229
+ # values in +html_options+ are passed through to the button element. For
230
+ # example, passing a +:class+ option within +html_options+ will set the
231
+ # class attribute of the button element.
232
+ #
233
+ # The class attribute of the form element can be set by passing a
234
+ # +:form_class+ option within +html_options+. It defaults to
235
+ # <tt>"button_to"</tt> to allow styling of the form and its children.
236
+ #
237
+ # The form submits a POST request by default. You can specify a different
238
+ # HTTP verb via the +:method+ option within +html_options+.
224
239
  #
225
240
  # ==== Options
226
- # The +options+ hash accepts the same options as +url_for+.
241
+ # The +options+ hash accepts the same options as +url_for+. To generate a
242
+ # <tt><form></tt> element without an <tt>[action]</tt> attribute, pass
243
+ # <tt>false</tt>:
244
+ #
245
+ # <%= button_to "New", false %>
246
+ # # => "<form method="post" class="button_to">
247
+ # # <button type="submit">New</button>
248
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
249
+ # # </form>"
250
+ #
251
+ # Most values in +html_options+ are passed through to the button element,
252
+ # but there are a few special options:
227
253
  #
228
- # There are a few special +html_options+:
229
254
  # * <tt>:method</tt> - \Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
230
255
  # <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
231
256
  # * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
@@ -250,12 +275,21 @@ module ActionView
250
275
  # ==== Examples
251
276
  # <%= button_to "New", action: "new" %>
252
277
  # # => "<form method="post" action="/controller/new" class="button_to">
253
- # # <input value="New" type="submit" />
278
+ # # <button type="submit">New</button>
279
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
254
280
  # # </form>"
255
281
  #
256
282
  # <%= button_to "New", new_article_path %>
257
283
  # # => "<form method="post" action="/articles/new" class="button_to">
258
- # # <input value="New" type="submit" />
284
+ # # <button type="submit">New</button>
285
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
286
+ # # </form>"
287
+ #
288
+ # <%= button_to "New", new_article_path, params: { time: Time.now } %>
289
+ # # => "<form method="post" action="/articles/new" class="button_to">
290
+ # # <button type="submit">New</button>
291
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
292
+ # # <input type="hidden" name="time" value="2021-04-08 14:06:09 -0500">
259
293
  # # </form>"
260
294
  #
261
295
  # <%= button_to [:make_happy, @user] do %>
@@ -265,49 +299,54 @@ module ActionView
265
299
  # # <button type="submit">
266
300
  # # Make happy <strong><%= @user.name %></strong>
267
301
  # # </button>
302
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
268
303
  # # </form>"
269
304
  #
270
305
  # <%= button_to "New", { action: "new" }, form_class: "new-thing" %>
271
306
  # # => "<form method="post" action="/controller/new" class="new-thing">
272
- # # <input value="New" type="submit" />
307
+ # # <button type="submit">New</button>
308
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
273
309
  # # </form>"
274
310
  #
275
- #
276
311
  # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
277
312
  # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
278
- # # <input value="Create" type="submit" />
313
+ # # <button type="submit">Create</button>
279
314
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
280
315
  # # </form>"
281
316
  #
282
- #
283
317
  # <%= button_to "Delete Image", { action: "delete", id: @image.id },
284
318
  # method: :delete, data: { confirm: "Are you sure?" } %>
285
319
  # # => "<form method="post" action="/images/delete/1" class="button_to">
286
320
  # # <input type="hidden" name="_method" value="delete" />
287
- # # <input data-confirm='Are you sure?' value="Delete Image" type="submit" />
321
+ # # <button data-confirm='Are you sure?' type="submit">Delete Image</button>
288
322
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
289
323
  # # </form>"
290
324
  #
291
- #
292
325
  # <%= button_to('Destroy', 'http://www.example.com',
293
326
  # method: :delete, remote: true, data: { confirm: 'Are you sure?', disable_with: 'loading...' }) %>
294
327
  # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
295
328
  # # <input name='_method' value='delete' type='hidden' />
296
- # # <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
329
+ # # <button type='submit' data-disable-with='loading...' data-confirm='Are you sure?'>Destroy</button>
297
330
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
298
331
  # # </form>"
299
332
  # #
300
333
  def button_to(name = nil, options = nil, html_options = nil, &block)
301
334
  html_options, options = options, name if block_given?
302
- options ||= {}
303
335
  html_options ||= {}
304
336
  html_options = html_options.stringify_keys
305
337
 
306
- url = options.is_a?(String) ? options : url_for(options)
338
+ url =
339
+ case options
340
+ when FalseClass then nil
341
+ else url_for(options)
342
+ end
343
+
307
344
  remote = html_options.delete("remote")
308
345
  params = html_options.delete("params")
309
346
 
310
- method = html_options.delete("method").to_s
347
+ authenticity_token = html_options.delete("authenticity_token")
348
+
349
+ method = (html_options.delete("method").presence || method_for_options(options)).to_s
311
350
  method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
312
351
 
313
352
  form_method = method == "get" ? "get" : "post"
@@ -319,7 +358,7 @@ module ActionView
319
358
 
320
359
  request_token_tag = if form_method == "post"
321
360
  request_method = method.empty? ? "post" : method
322
- token_tag(nil, form_options: { action: url, method: request_method })
361
+ token_tag(authenticity_token, form_options: { action: url, method: request_method })
323
362
  else
324
363
  ""
325
364
  end
@@ -327,8 +366,8 @@ module ActionView
327
366
  html_options = convert_options_to_data_attributes(options, html_options)
328
367
  html_options["type"] = "submit"
329
368
 
330
- button = if block_given?
331
- content_tag("button", html_options, &block)
369
+ button = if block_given? || button_to_generates_button_tag
370
+ content_tag("button", name || url, html_options, &block)
332
371
  else
333
372
  html_options["value"] = name || url
334
373
  tag("input", html_options)
@@ -337,7 +376,8 @@ module ActionView
337
376
  inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
338
377
  if params
339
378
  to_form_params(params).each do |param|
340
- inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value])
379
+ inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value],
380
+ autocomplete: "off")
341
381
  end
342
382
  end
343
383
  content_tag("form", inner_tags, form_options)
@@ -466,9 +506,9 @@ module ActionView
466
506
  # mail_to "me@domain.com", "My email"
467
507
  # # => <a href="mailto:me@domain.com">My email</a>
468
508
  #
469
- # mail_to "me@domain.com", "My email", cc: "ccaddress@domain.com",
509
+ # mail_to "me@domain.com", cc: "ccaddress@domain.com",
470
510
  # subject: "This is an example email"
471
- # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
511
+ # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">me@domain.com</a>
472
512
  #
473
513
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
474
514
  #
@@ -479,7 +519,7 @@ module ActionView
479
519
  # <strong>Email me:</strong> <span>me@domain.com</span>
480
520
  # </a>
481
521
  def mail_to(email_address, name = nil, html_options = {}, &block)
482
- html_options, name = name, nil if block_given?
522
+ html_options, name = name, nil if name.is_a?(Hash)
483
523
  html_options = (html_options || {}).stringify_keys
484
524
 
485
525
  extras = %w{ cc bcc body subject reply_to }.map! { |item|
@@ -559,16 +599,14 @@ module ActionView
559
599
  request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
560
600
  request_uri = URI::DEFAULT_PARSER.unescape(request_uri).force_encoding(Encoding::BINARY)
561
601
 
562
- if url_string.start_with?("/") && url_string != "/"
563
- url_string.chomp!("/")
564
- request_uri.chomp!("/")
565
- end
566
-
567
602
  if %r{^\w+://}.match?(url_string)
568
- url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
569
- else
570
- url_string == request_uri
603
+ request_uri = +"#{request.protocol}#{request.host_with_port}#{request_uri}"
571
604
  end
605
+
606
+ remove_trailing_slash!(url_string)
607
+ remove_trailing_slash!(request_uri)
608
+
609
+ url_string == request_uri
572
610
  end
573
611
 
574
612
  if RUBY_VERSION.start_with?("2.7")
@@ -584,29 +622,37 @@ module ActionView
584
622
  end
585
623
  end
586
624
 
587
- # Creates an SMS anchor link tag to the specified +phone_number+, which is
588
- # also used as the name of the link unless +name+ is specified. Additional
589
- # HTML attributes for the link can be passed in +html_options+.
625
+ # Creates an SMS anchor link tag to the specified +phone_number+. When the
626
+ # link is clicked, the default SMS messaging app is opened ready to send a
627
+ # message to the linked phone number. If the +body+ option is specified,
628
+ # the contents of the message will be preset to +body+.
590
629
  #
591
- # When clicked, an SMS message is prepopulated with the passed phone number
592
- # and optional +body+ value.
630
+ # If +name+ is not specified, +phone_number+ will be used as the name of
631
+ # the link.
593
632
  #
594
- # +sms_to+ has a +body+ option for customizing the SMS message itself by
595
- # passing special keys to +html_options+.
633
+ # A +country_code+ option is supported, which prepends a plus sign and the
634
+ # given country code to the linked phone number. For example,
635
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
636
+ # phone number.
637
+ #
638
+ # Additional HTML attributes for the link can be passed via +html_options+.
596
639
  #
597
640
  # ==== Options
641
+ # * <tt>:country_code</tt> - Prepend the country code to the phone number.
598
642
  # * <tt>:body</tt> - Preset the body of the message.
599
643
  #
600
644
  # ==== Examples
601
645
  # sms_to "5155555785"
602
646
  # # => <a href="sms:5155555785;">5155555785</a>
603
647
  #
648
+ # sms_to "5155555785", country_code: "01"
649
+ # # => <a href="sms:+015155555785;">5155555785</a>
650
+ #
604
651
  # sms_to "5155555785", "Text me"
605
652
  # # => <a href="sms:5155555785;">Text me</a>
606
653
  #
607
- # sms_to "5155555785", "Text me",
608
- # body: "Hello Jim I have a question about your product."
609
- # # => <a href="sms:5155555785;?body=Hello%20Jim%20I%20have%20a%20question%20about%20your%20product">Text me</a>
654
+ # sms_to "5155555785", body: "I have a question about your product."
655
+ # # => <a href="sms:5155555785;?body=I%20have%20a%20question%20about%20your%20product">5155555785</a>
610
656
  #
611
657
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
612
658
  #
@@ -617,46 +663,47 @@ module ActionView
617
663
  # <strong>Text me:</strong>
618
664
  # </a>
619
665
  def sms_to(phone_number, name = nil, html_options = {}, &block)
620
- html_options, name = name, nil if block_given?
666
+ html_options, name = name, nil if name.is_a?(Hash)
621
667
  html_options = (html_options || {}).stringify_keys
622
668
 
623
- extras = %w{ body }.map! { |item|
624
- option = html_options.delete(item).presence || next
625
- "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
626
- }.compact
627
- extras = extras.empty? ? "" : "?&" + extras.join("&")
669
+ country_code = html_options.delete("country_code").presence
670
+ country_code = country_code ? "+#{ERB::Util.url_encode(country_code)}" : ""
671
+
672
+ body = html_options.delete("body").presence
673
+ body = body ? "?&body=#{ERB::Util.url_encode(body)}" : ""
628
674
 
629
675
  encoded_phone_number = ERB::Util.url_encode(phone_number)
630
- html_options["href"] = "sms:#{encoded_phone_number};#{extras}"
676
+ html_options["href"] = "sms:#{country_code}#{encoded_phone_number};#{body}"
631
677
 
632
678
  content_tag("a", name || phone_number, html_options, &block)
633
679
  end
634
680
 
635
- # Creates a TEL anchor link tag to the specified +phone_number+, which is
636
- # also used as the name of the link unless +name+ is specified. Additional
637
- # HTML attributes for the link can be passed in +html_options+.
681
+ # Creates a TEL anchor link tag to the specified +phone_number+. When the
682
+ # link is clicked, the default app to make phone calls is opened and
683
+ # prepopulated with the phone number.
638
684
  #
639
- # When clicked, the default app to make calls is opened, and it
640
- # is prepopulated with the passed phone number and optional
641
- # +country_code+ value.
685
+ # If +name+ is not specified, +phone_number+ will be used as the name of
686
+ # the link.
642
687
  #
643
- # +phone_to+ has an optional +country_code+ option which automatically adds the country
644
- # code as well as the + sign in the phone numer that gets prepopulated,
645
- # for example if +country_code: "01"+ +\+01+ will be prepended to the
646
- # phone numer, by passing special keys to +html_options+.
688
+ # A +country_code+ option is supported, which prepends a plus sign and the
689
+ # given country code to the linked phone number. For example,
690
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
691
+ # phone number.
692
+ #
693
+ # Additional HTML attributes for the link can be passed via +html_options+.
647
694
  #
648
695
  # ==== Options
649
- # * <tt>:country_code</tt> - Prepends the country code to the number
696
+ # * <tt>:country_code</tt> - Prepends the country code to the phone number
650
697
  #
651
698
  # ==== Examples
652
699
  # phone_to "1234567890"
653
700
  # # => <a href="tel:1234567890">1234567890</a>
654
701
  #
655
702
  # phone_to "1234567890", "Phone me"
656
- # # => <a href="tel:134567890">Phone me</a>
703
+ # # => <a href="tel:1234567890">Phone me</a>
657
704
  #
658
- # phone_to "1234567890", "Phone me", country_code: "01"
659
- # # => <a href="tel:+015155555785">Phone me</a>
705
+ # phone_to "1234567890", country_code: "01"
706
+ # # => <a href="tel:+011234567890">1234567890</a>
660
707
  #
661
708
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
662
709
  #
@@ -667,7 +714,7 @@ module ActionView
667
714
  # <strong>Phone me:</strong>
668
715
  # </a>
669
716
  def phone_to(phone_number, name = nil, html_options = {}, &block)
670
- html_options, name = name, nil if block_given?
717
+ html_options, name = name, nil if name.is_a?(Hash)
671
718
  html_options = (html_options || {}).stringify_keys
672
719
 
673
720
  country_code = html_options.delete("country_code").presence
@@ -695,6 +742,14 @@ module ActionView
695
742
  end
696
743
  end
697
744
 
745
+ def url_target(name, options)
746
+ if name.respond_to?(:model_name) && options.empty?
747
+ url_for(name)
748
+ else
749
+ url_for(options)
750
+ end
751
+ end
752
+
698
753
  def link_to_remote_options?(options)
699
754
  if options.is_a?(Hash)
700
755
  options.delete("remote") || options.delete(:remote)
@@ -712,6 +767,16 @@ module ActionView
712
767
  html_options["data-method"] = method
713
768
  end
714
769
 
770
+ def method_for_options(options)
771
+ if options.is_a?(Array)
772
+ method_for_options(options.last)
773
+ elsif options.respond_to?(:persisted?)
774
+ options.persisted? ? :patch : :post
775
+ elsif options.respond_to?(:to_model)
776
+ method_for_options(options.to_model)
777
+ end
778
+ end
779
+
715
780
  STRINGIFIED_COMMON_METHODS = {
716
781
  get: "get",
717
782
  delete: "delete",
@@ -727,15 +792,20 @@ module ActionView
727
792
 
728
793
  def token_tag(token = nil, form_options: {})
729
794
  if token != false && defined?(protect_against_forgery?) && protect_against_forgery?
730
- token ||= form_authenticity_token(form_options: form_options)
731
- tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
795
+ token =
796
+ if token == true || token.nil?
797
+ form_authenticity_token(form_options: form_options.merge(authenticity_token: token))
798
+ else
799
+ token
800
+ end
801
+ tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token, autocomplete: "off")
732
802
  else
733
803
  ""
734
804
  end
735
805
  end
736
806
 
737
807
  def method_tag(method)
738
- tag("input", type: "hidden", name: "_method", value: method.to_s)
808
+ tag("input", type: "hidden", name: "_method", value: method.to_s, autocomplete: "off")
739
809
  end
740
810
 
741
811
  # Returns an array of hashes each containing :name and :value keys
@@ -779,6 +849,11 @@ module ActionView
779
849
 
780
850
  params.sort_by { |pair| pair[:name] }
781
851
  end
852
+
853
+ def remove_trailing_slash!(url_string)
854
+ trailing_index = (url_string.index("?") || 0) - 1
855
+ url_string[trailing_index] = "" if url_string[trailing_index] == "/"
856
+ end
782
857
  end
783
858
  end
784
859
  end
@@ -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!