actionview 4.2.11.1 → 6.0.4

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +201 -192
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +144 -37
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +54 -20
  10. data/lib/action_view/digestor.rb +88 -85
  11. data/lib/action_view/flows.rb +11 -12
  12. data/lib/action_view/gem_version.rb +6 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +16 -11
  14. data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
  15. data/lib/action_view/helpers/asset_url_helper.rb +171 -67
  16. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  17. data/lib/action_view/helpers/cache_helper.rb +112 -42
  18. data/lib/action_view/helpers/capture_helper.rb +20 -13
  19. data/lib/action_view/helpers/controller_helper.rb +15 -4
  20. data/lib/action_view/helpers/csp_helper.rb +26 -0
  21. data/lib/action_view/helpers/csrf_helper.rb +8 -6
  22. data/lib/action_view/helpers/date_helper.rb +230 -129
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +755 -129
  25. data/lib/action_view/helpers/form_options_helper.rb +130 -75
  26. data/lib/action_view/helpers/form_tag_helper.rb +116 -71
  27. data/lib/action_view/helpers/javascript_helper.rb +30 -14
  28. data/lib/action_view/helpers/number_helper.rb +84 -59
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +11 -8
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +201 -75
  33. data/lib/action_view/helpers/tags/base.rb +138 -98
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -19
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +4 -3
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +37 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -1
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -6
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +14 -9
  58. data/lib/action_view/helpers/tags/select.rb +11 -10
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -8
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -1
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +15 -16
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -1
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +56 -38
  70. data/lib/action_view/helpers/translation_helper.rb +91 -47
  71. data/lib/action_view/helpers/url_helper.rb +160 -105
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +65 -61
  74. data/lib/action_view/log_subscriber.rb +61 -10
  75. data/lib/action_view/lookup_context.rb +147 -89
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +28 -23
  78. data/lib/action_view/railtie.rb +62 -6
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +71 -13
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +239 -225
  83. data/lib/action_view/renderer/renderer.rb +22 -8
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
  85. data/lib/action_view/renderer/template_renderer.rb +79 -73
  86. data/lib/action_view/rendering.rb +68 -44
  87. data/lib/action_view/routing_url_for.rb +33 -22
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +44 -29
  90. data/lib/action_view/template/handlers/builder.rb +12 -13
  91. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  92. data/lib/action_view/template/handlers/erb.rb +24 -86
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +4 -4
  95. data/lib/action_view/template/handlers.rb +38 -8
  96. data/lib/action_view/template/html.rb +19 -10
  97. data/lib/action_view/template/inline.rb +22 -0
  98. data/lib/action_view/template/raw_file.rb +28 -0
  99. data/lib/action_view/template/resolver.rb +217 -193
  100. data/lib/action_view/template/sources/file.rb +17 -0
  101. data/lib/action_view/template/sources.rb +13 -0
  102. data/lib/action_view/template/text.rb +11 -10
  103. data/lib/action_view/template/types.rb +18 -18
  104. data/lib/action_view/template.rb +146 -90
  105. data/lib/action_view/test_case.rb +52 -32
  106. data/lib/action_view/testing/resolvers.rb +46 -34
  107. data/lib/action_view/unbound_template.rb +31 -0
  108. data/lib/action_view/version.rb +3 -1
  109. data/lib/action_view/view_paths.rb +48 -31
  110. data/lib/action_view.rb +11 -8
  111. data/lib/assets/compiled/rails-ujs.js +746 -0
  112. metadata +38 -29
  113. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  114. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,7 +1,9 @@
1
- require 'action_view/helpers/javascript_helper'
2
- require 'active_support/core_ext/array/access'
3
- require 'active_support/core_ext/hash/keys'
4
- require 'active_support/core_ext/string/output_safety'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_view/helpers/javascript_helper"
4
+ require "active_support/core_ext/array/access"
5
+ require "active_support/core_ext/hash/keys"
6
+ require "active_support/core_ext/string/output_safety"
5
7
 
6
8
  module ActionView
7
9
  # = Action View URL Helpers
@@ -35,20 +37,30 @@ module ActionView
35
37
  when :back
36
38
  _back_url
37
39
  else
38
- raise ArgumentError, "arguments passed to url_for can't be handled. Please require " +
40
+ raise ArgumentError, "arguments passed to url_for can't be handled. Please require " \
39
41
  "routes or provide your own implementation"
40
42
  end
41
43
  end
42
44
 
43
45
  def _back_url # :nodoc:
44
- referrer = controller.respond_to?(:request) && controller.request.env["HTTP_REFERER"]
45
- referrer || 'javascript:history.back()'
46
+ _filtered_referrer || "javascript:history.back()"
46
47
  end
47
48
  protected :_back_url
48
49
 
49
- # Creates a link tag of the given +name+ using a URL created by the set of +options+.
50
+ def _filtered_referrer # :nodoc:
51
+ if controller.respond_to?(:request)
52
+ referrer = controller.request.env["HTTP_REFERER"]
53
+ if referrer && URI(referrer).scheme != "javascript"
54
+ referrer
55
+ end
56
+ end
57
+ rescue URI::InvalidURIError
58
+ end
59
+ protected :_filtered_referrer
60
+
61
+ # Creates an anchor element of the given +name+ using a URL created by the set of +options+.
50
62
  # See the valid options in the documentation for +url_for+. It's also possible to
51
- # pass a String instead of an options hash, which generates a link tag that uses the
63
+ # pass a String instead of an options hash, which generates an anchor element that uses the
52
64
  # value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead
53
65
  # of an options hash will generate a link to the referrer (a JavaScript back link
54
66
  # will be used in place of a referrer if none exists). If +nil+ is passed as the name
@@ -95,10 +107,9 @@ module ActionView
95
107
  # driver to prompt with the question specified (in this case, the
96
108
  # resulting text would be <tt>question?</tt>. If the user accepts, the
97
109
  # link is processed normally, otherwise no action is taken.
98
- # * <tt>:disable_with</tt> - Value of this parameter will be
99
- # used as the value for a disabled version of the submit
100
- # button when the form is submitted. This feature is provided
101
- # by the unobtrusive JavaScript driver.
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.
102
113
  #
103
114
  # ==== Examples
104
115
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
@@ -128,6 +139,11 @@ module ActionView
128
139
  # link_to "Profiles", controller: "profiles"
129
140
  # # => <a href="/profiles">Profiles</a>
130
141
  #
142
+ # When name is +nil+ the href is presented instead
143
+ #
144
+ # link_to nil, "http://example.com"
145
+ # # => <a href="http://www.example.com">http://www.example.com</a>
146
+ #
131
147
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
132
148
  #
133
149
  # <%= link_to(@profile) do %>
@@ -172,6 +188,11 @@ module ActionView
172
188
  #
173
189
  # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
174
190
  # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
191
+ #
192
+ # Also you can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
193
+ #
194
+ # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
195
+ # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
175
196
  def link_to(name = nil, options = nil, html_options = nil, &block)
176
197
  html_options, options, name = options, name, block if block_given?
177
198
  options ||= {}
@@ -179,9 +200,9 @@ module ActionView
179
200
  html_options = convert_options_to_data_attributes(options, html_options)
180
201
 
181
202
  url = url_for(options)
182
- html_options['href'] ||= url
203
+ html_options["href"] ||= url
183
204
 
184
- content_tag(:a, name || url, html_options, &block)
205
+ content_tag("a", name || url, html_options, &block)
185
206
  end
186
207
 
187
208
  # Generates a form containing a single button that submits to the URL created
@@ -232,7 +253,7 @@ module ActionView
232
253
  # # <input value="New" type="submit" />
233
254
  # # </form>"
234
255
  #
235
- # <%= button_to "New", new_articles_path %>
256
+ # <%= button_to "New", new_article_path %>
236
257
  # # => "<form method="post" action="/articles/new" class="button_to">
237
258
  # # <input value="New" type="submit" />
238
259
  # # </form>"
@@ -280,42 +301,46 @@ module ActionView
280
301
  html_options, options = options, name if block_given?
281
302
  options ||= {}
282
303
  html_options ||= {}
283
-
284
304
  html_options = html_options.stringify_keys
285
- convert_boolean_attributes!(html_options, %w(disabled))
286
305
 
287
306
  url = options.is_a?(String) ? options : url_for(options)
288
- remote = html_options.delete('remote')
289
- params = html_options.delete('params')
290
-
291
- method = html_options.delete('method').to_s
292
- method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.html_safe
293
-
294
- form_method = method == 'get' ? 'get' : 'post'
295
- form_options = html_options.delete('form') || {}
296
- form_options[:class] ||= html_options.delete('form_class') || 'button_to'
297
- form_options.merge!(method: form_method, action: url)
298
- form_options.merge!("data-remote" => "true") if remote
299
-
300
- request_token_tag = form_method == 'post' ? token_tag : ''
307
+ remote = html_options.delete("remote")
308
+ params = html_options.delete("params")
309
+
310
+ method = html_options.delete("method").to_s
311
+ method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
312
+
313
+ form_method = method == "get" ? "get" : "post"
314
+ form_options = html_options.delete("form") || {}
315
+ form_options[:class] ||= html_options.delete("form_class") || "button_to"
316
+ form_options[:method] = form_method
317
+ form_options[:action] = url
318
+ form_options[:'data-remote'] = true if remote
319
+
320
+ request_token_tag = if form_method == "post"
321
+ request_method = method.empty? ? "post" : method
322
+ token_tag(nil, form_options: { action: url, method: request_method })
323
+ else
324
+ ""
325
+ end
301
326
 
302
327
  html_options = convert_options_to_data_attributes(options, html_options)
303
- html_options['type'] = 'submit'
328
+ html_options["type"] = "submit"
304
329
 
305
330
  button = if block_given?
306
- content_tag('button', html_options, &block)
331
+ content_tag("button", html_options, &block)
307
332
  else
308
- html_options['value'] = name || url
309
- tag('input', html_options)
333
+ html_options["value"] = name || url
334
+ tag("input", html_options)
310
335
  end
311
336
 
312
337
  inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
313
338
  if params
314
- params.each do |param_name, value|
315
- inner_tags.safe_concat tag(:input, type: "hidden", name: param_name, value: value.to_param)
339
+ to_form_params(params).each do |param|
340
+ inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value])
316
341
  end
317
342
  end
318
- content_tag('form', inner_tags, form_options)
343
+ content_tag("form", inner_tags, form_options)
319
344
  end
320
345
 
321
346
  # Creates a link tag of the given +name+ using a URL created by the set of
@@ -428,6 +453,7 @@ module ActionView
428
453
  # * <tt>:body</tt> - Preset the body of the email.
429
454
  # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
430
455
  # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
456
+ # * <tt>:reply_to</tt> - Preset the Reply-To field of the email.
431
457
  #
432
458
  # ==== Obfuscation
433
459
  # Prior to Rails 4.0, +mail_to+ provided options for encoding the address
@@ -457,73 +483,64 @@ module ActionView
457
483
  html_options, name = name, nil if block_given?
458
484
  html_options = (html_options || {}).stringify_keys
459
485
 
460
- extras = %w{ cc bcc body subject }.map! { |item|
461
- option = html_options.delete(item) || next
462
- "#{item}=#{Rack::Utils.escape_path(option)}"
486
+ extras = %w{ cc bcc body subject reply_to }.map! { |item|
487
+ option = html_options.delete(item).presence || next
488
+ "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
463
489
  }.compact
464
- extras = extras.empty? ? '' : '?' + extras.join('&')
490
+ extras = extras.empty? ? "" : "?" + extras.join("&")
465
491
 
466
- encoded_email_address = ERB::Util.url_encode(email_address ? email_address.to_str : '').gsub("%40", "@")
492
+ encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
467
493
  html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
468
494
 
469
- content_tag(:a, name || email_address, html_options, &block)
495
+ content_tag("a", name || email_address, html_options, &block)
470
496
  end
471
497
 
472
498
  # True if the current request URI was generated by the given +options+.
473
499
  #
474
500
  # ==== Examples
475
- # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc</tt> action.
501
+ # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc&page=1</tt> action.
476
502
  #
477
503
  # current_page?(action: 'process')
478
504
  # # => false
479
505
  #
480
- # current_page?(controller: 'shop', action: 'checkout')
481
- # # => true
482
- #
483
- # current_page?(controller: 'shop', action: 'checkout', order: 'asc')
484
- # # => false
485
- #
486
506
  # current_page?(action: 'checkout')
487
507
  # # => true
488
508
  #
489
509
  # current_page?(controller: 'library', action: 'checkout')
490
510
  # # => false
491
511
  #
492
- # current_page?('http://www.example.com/shop/checkout')
493
- # # => true
494
- #
495
- # current_page?('/shop/checkout')
512
+ # current_page?(controller: 'shop', action: 'checkout')
496
513
  # # => true
497
514
  #
498
- # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc&page=1</tt> action.
499
- #
500
- # current_page?(action: 'process')
515
+ # current_page?(controller: 'shop', action: 'checkout', order: 'asc')
501
516
  # # => false
502
517
  #
503
- # current_page?(controller: 'shop', action: 'checkout')
504
- # # => true
505
- #
506
518
  # current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '1')
507
519
  # # => true
508
520
  #
509
521
  # current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '2')
510
522
  # # => false
511
523
  #
512
- # current_page?(controller: 'shop', action: 'checkout', order: 'desc')
524
+ # current_page?('http://www.example.com/shop/checkout')
525
+ # # => true
526
+ #
527
+ # current_page?('http://www.example.com/shop/checkout', check_parameters: true)
513
528
  # # => false
514
529
  #
515
- # current_page?(action: 'checkout')
530
+ # current_page?('/shop/checkout')
516
531
  # # => true
517
532
  #
518
- # current_page?(controller: 'library', action: 'checkout')
519
- # # => false
533
+ # current_page?('http://www.example.com/shop/checkout?order=desc&page=1')
534
+ # # => true
520
535
  #
521
536
  # Let's say we're in the <tt>http://www.example.com/products</tt> action with method POST in case of invalid product.
522
537
  #
523
538
  # current_page?(controller: 'product', action: 'index')
524
539
  # # => false
525
540
  #
526
- def current_page?(options)
541
+ # We can also pass in the symbol arguments instead of strings.
542
+ #
543
+ def current_page?(options, check_parameters: false)
527
544
  unless request
528
545
  raise "You cannot use helpers that need to determine the current " \
529
546
  "page unless your view context provides a Request object " \
@@ -532,15 +549,22 @@ module ActionView
532
549
 
533
550
  return false unless request.get? || request.head?
534
551
 
552
+ check_parameters ||= options.is_a?(Hash) && options.delete(:check_parameters)
535
553
  url_string = URI.parser.unescape(url_for(options)).force_encoding(Encoding::BINARY)
536
554
 
537
555
  # We ignore any extra parameters in the request_uri if the
538
- # submitted url doesn't have any either. This lets the function
556
+ # submitted URL doesn't have any either. This lets the function
539
557
  # work with things like ?order=asc
540
- request_uri = url_string.index("?") ? request.fullpath : request.path
558
+ # the behaviour can be disabled with check_parameters: true
559
+ request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
541
560
  request_uri = URI.parser.unescape(request_uri).force_encoding(Encoding::BINARY)
542
561
 
543
- if url_string =~ /^\w+:\/\//
562
+ if url_string.start_with?("/") && url_string != "/"
563
+ url_string.chomp!("/")
564
+ request_uri.chomp!("/")
565
+ end
566
+
567
+ if %r{^\w+://}.match?(url_string)
544
568
  url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
545
569
  else
546
570
  url_string == request_uri
@@ -551,70 +575,101 @@ module ActionView
551
575
  def convert_options_to_data_attributes(options, html_options)
552
576
  if html_options
553
577
  html_options = html_options.stringify_keys
554
- html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
578
+ html_options["data-remote"] = "true" if link_to_remote_options?(options) || link_to_remote_options?(html_options)
555
579
 
556
- method = html_options.delete('method')
580
+ method = html_options.delete("method")
557
581
 
558
582
  add_method_to_attributes!(html_options, method) if method
559
583
 
560
584
  html_options
561
585
  else
562
- link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
586
+ link_to_remote_options?(options) ? { "data-remote" => "true" } : {}
563
587
  end
564
588
  end
565
589
 
566
590
  def link_to_remote_options?(options)
567
591
  if options.is_a?(Hash)
568
- options.delete('remote') || options.delete(:remote)
592
+ options.delete("remote") || options.delete(:remote)
569
593
  end
570
594
  end
571
595
 
572
596
  def add_method_to_attributes!(html_options, method)
573
- if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
574
- html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip
597
+ if method_not_get_method?(method) && html_options["rel"] !~ /nofollow/
598
+ if html_options["rel"].blank?
599
+ html_options["rel"] = "nofollow"
600
+ else
601
+ html_options["rel"] = "#{html_options["rel"]} nofollow"
602
+ end
575
603
  end
576
604
  html_options["data-method"] = method
577
605
  end
578
606
 
579
- # Processes the +html_options+ hash, converting the boolean
580
- # attributes from true/false form into the form required by
581
- # HTML/XHTML. (An attribute is considered to be boolean if
582
- # its name is listed in the given +bool_attrs+ array.)
583
- #
584
- # More specifically, for each boolean attribute in +html_options+
585
- # given as:
607
+ STRINGIFIED_COMMON_METHODS = {
608
+ get: "get",
609
+ delete: "delete",
610
+ patch: "patch",
611
+ post: "post",
612
+ put: "put",
613
+ }.freeze
614
+
615
+ def method_not_get_method?(method)
616
+ return false unless method
617
+ (STRINGIFIED_COMMON_METHODS[method] || method.to_s.downcase) != "get"
618
+ end
619
+
620
+ def token_tag(token = nil, form_options: {})
621
+ if token != false && defined?(protect_against_forgery?) && protect_against_forgery?
622
+ token ||= form_authenticity_token(form_options: form_options)
623
+ tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
624
+ else
625
+ ""
626
+ end
627
+ end
628
+
629
+ def method_tag(method)
630
+ tag("input", type: "hidden", name: "_method", value: method.to_s)
631
+ end
632
+
633
+ # Returns an array of hashes each containing :name and :value keys
634
+ # suitable for use as the names and values of form input fields:
586
635
  #
587
- # "attr" => bool_value
636
+ # to_form_params(name: 'David', nationality: 'Danish')
637
+ # # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}]
588
638
  #
589
- # if the associated +bool_value+ evaluates to true, it is
590
- # replaced with the attribute's name; otherwise the attribute is
591
- # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
592
- # section 4.5 "Attribute Minimization" for more:
593
- # http://www.w3.org/TR/xhtml1/#h-4.5)
639
+ # to_form_params(country: { name: 'Denmark' })
640
+ # # => [{name: 'country[name]', value: 'Denmark'}]
594
641
  #
595
- # Returns the updated +html_options+ hash, which is also modified
596
- # in place.
642
+ # to_form_params(countries: ['Denmark', 'Sweden']})
643
+ # # => [{name: 'countries[]', value: 'Denmark'}, {name: 'countries[]', value: 'Sweden'}]
597
644
  #
598
- # Example:
645
+ # An optional namespace can be passed to enclose key names:
599
646
  #
600
- # convert_boolean_attributes!( html_options,
601
- # %w( checked disabled readonly ) )
602
- def convert_boolean_attributes!(html_options, bool_attrs)
603
- bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
604
- html_options
605
- end
647
+ # to_form_params({ name: 'Denmark' }, 'country')
648
+ # # => [{name: 'country[name]', value: 'Denmark'}]
649
+ def to_form_params(attribute, namespace = nil)
650
+ attribute = if attribute.respond_to?(:permitted?)
651
+ attribute.to_h
652
+ else
653
+ attribute
654
+ end
606
655
 
607
- def token_tag(token=nil)
608
- if token != false && protect_against_forgery?
609
- token ||= form_authenticity_token
610
- tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
656
+ params = []
657
+ case attribute
658
+ when Hash
659
+ attribute.each do |key, value|
660
+ prefix = namespace ? "#{namespace}[#{key}]" : key
661
+ params.push(*to_form_params(value, prefix))
662
+ end
663
+ when Array
664
+ array_prefix = "#{namespace}[]"
665
+ attribute.each do |value|
666
+ params.push(*to_form_params(value, array_prefix))
667
+ end
611
668
  else
612
- ''
669
+ params << { name: namespace.to_s, value: attribute.to_param }
613
670
  end
614
- end
615
671
 
616
- def method_tag(method)
617
- tag('input', type: 'hidden', name: '_method', value: method.to_s)
672
+ params.sort_by { |pair| pair[:name] }
618
673
  end
619
674
  end
620
675
  end
@@ -1,4 +1,6 @@
1
- require 'active_support/benchmarkable'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/benchmarkable"
2
4
 
3
5
  module ActionView #:nodoc:
4
6
  module Helpers #:nodoc:
@@ -11,6 +13,7 @@ module ActionView #:nodoc:
11
13
  autoload :CacheHelper
12
14
  autoload :CaptureHelper
13
15
  autoload :ControllerHelper
16
+ autoload :CspHelper
14
17
  autoload :CsrfHelper
15
18
  autoload :DateHelper
16
19
  autoload :DebugHelper
@@ -20,7 +23,6 @@ module ActionView #:nodoc:
20
23
  autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
21
24
  autoload :NumberHelper
22
25
  autoload :OutputSafetyHelper
23
- autoload :RecordTagHelper
24
26
  autoload :RenderingHelper
25
27
  autoload :SanitizeHelper
26
28
  autoload :TagHelper
@@ -44,6 +46,7 @@ module ActionView #:nodoc:
44
46
  include CacheHelper
45
47
  include CaptureHelper
46
48
  include ControllerHelper
49
+ include CspHelper
47
50
  include CsrfHelper
48
51
  include DateHelper
49
52
  include DebugHelper
@@ -53,7 +56,6 @@ module ActionView #:nodoc:
53
56
  include JavaScriptHelper
54
57
  include NumberHelper
55
58
  include OutputSafetyHelper
56
- include RecordTagHelper
57
59
  include RenderingHelper
58
60
  include SanitizeHelper
59
61
  include TagHelper