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
@@ -2,21 +2,21 @@
2
2
 
3
3
  require "cgi"
4
4
  require "erb"
5
- require "action_view/helpers/form_helper"
6
5
  require "active_support/core_ext/string/output_safety"
7
6
  require "active_support/core_ext/array/extract_options"
8
7
  require "active_support/core_ext/array/wrap"
8
+ require "action_view/helpers/text_helper"
9
9
 
10
10
  module ActionView
11
11
  # = Action View Form Option Helpers
12
- module Helpers #:nodoc:
12
+ module Helpers # :nodoc:
13
13
  # Provides a number of methods for turning different kinds of containers into a set of option tags.
14
14
  #
15
15
  # The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
16
16
  #
17
17
  # * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
18
18
  #
19
- # select("post", "category", Post::CATEGORIES, { include_blank: true })
19
+ # select(:post, :category, Post::CATEGORIES, { include_blank: true })
20
20
  #
21
21
  # could become:
22
22
  #
@@ -30,7 +30,7 @@ module ActionView
30
30
  #
31
31
  # Example with <tt>@post.person_id => 2</tt>:
32
32
  #
33
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: 'None' })
33
+ # select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: "None" })
34
34
  #
35
35
  # could become:
36
36
  #
@@ -43,7 +43,7 @@ module ActionView
43
43
  #
44
44
  # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
45
45
  #
46
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { prompt: 'Select Person' })
46
+ # select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { prompt: "Select Person" })
47
47
  #
48
48
  # could become:
49
49
  #
@@ -54,10 +54,10 @@ module ActionView
54
54
  # <option value="3">Rafael</option>
55
55
  # </select>
56
56
  #
57
- # * <tt>:index</tt> - like the other form helpers, +select+ can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, +select+ expects this
57
+ # * <tt>:index</tt> - like the other form helpers, <tt>select</tt> can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, <tt>select</tt> expects this
58
58
  # option to be in the +html_options+ parameter.
59
59
  #
60
- # select("album[]", "genre", %w[rap rock country], {}, { index: nil })
60
+ # select("album[]", :genre, %w[ rap rock country ], {}, { index: nil })
61
61
  #
62
62
  # becomes:
63
63
  #
@@ -69,7 +69,7 @@ module ActionView
69
69
  #
70
70
  # * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
71
71
  #
72
- # select("post", "category", Post::CATEGORIES, { disabled: 'restricted' })
72
+ # select(:post, :category, Post::CATEGORIES, { disabled: "restricted" })
73
73
  #
74
74
  # could become:
75
75
  #
@@ -90,7 +90,6 @@ module ActionView
90
90
  # <option value="3">Jokes</option>
91
91
  # <option value="4">Poems</option>
92
92
  # </select>
93
- #
94
93
  module FormOptionsHelper
95
94
  # ERB::Util can mask some helpers like textilize. Make sure to include them.
96
95
  include TextHelper
@@ -100,25 +99,22 @@ module ActionView
100
99
  #
101
100
  # There are two possible formats for the +choices+ parameter, corresponding to other helpers' output:
102
101
  #
103
- # * A flat collection (see +options_for_select+).
104
- #
105
- # * A nested collection (see +grouped_options_for_select+).
102
+ # * A flat collection (see <tt>options_for_select</tt>).
103
+ # * A nested collection (see <tt>grouped_options_for_select</tt>).
106
104
  #
107
- # For example:
105
+ # Example with <tt>@post.person_id => 2</tt>:
108
106
  #
109
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
107
+ # select :post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
110
108
  #
111
109
  # would become:
112
110
  #
113
111
  # <select name="post[person_id]" id="post_person_id">
114
112
  # <option value="" label=" "></option>
115
- # <option value="1" selected="selected">David</option>
116
- # <option value="2">Eileen</option>
113
+ # <option value="1">David</option>
114
+ # <option value="2" selected="selected">Eileen</option>
117
115
  # <option value="3">Rafael</option>
118
116
  # </select>
119
117
  #
120
- # assuming the associated person has ID 1.
121
- #
122
118
  # This can be used to provide a default set of options in the standard way: before rendering the create form, a
123
119
  # new model instance is assigned the default options and bound to @model_name. Usually this model is not saved
124
120
  # to the database. Instead, a second model object is created when the create request is received.
@@ -132,9 +128,9 @@ module ActionView
132
128
  # A block can be passed to +select+ to customize how the options tags will be rendered. This
133
129
  # is useful when the options tag has complex attributes.
134
130
  #
135
- # select(report, "campaign_ids") do
131
+ # select(report, :campaign_ids) do
136
132
  # available_campaigns.each do |c|
137
- # content_tag(:option, c.name, value: c.id, data: { tags: c.tags.to_json })
133
+ # tag.option(c.name, value: c.id, data: { tags: c.tags.to_json })
138
134
  # end
139
135
  # end
140
136
  #
@@ -159,7 +155,6 @@ module ActionView
159
155
  #
160
156
  # In case if you don't want the helper to generate this hidden field you can specify
161
157
  # <tt>include_hidden: false</tt> option.
162
- #
163
158
  def select(object, method, choices = nil, options = {}, html_options = {}, &block)
164
159
  Tags::Select.new(object, method, self, choices, options, html_options, &block).render
165
160
  end
@@ -183,6 +178,7 @@ module ActionView
183
178
  #
184
179
  # class Author < ActiveRecord::Base
185
180
  # has_many :posts
181
+ #
186
182
  # def name_with_initial
187
183
  # "#{first_name.first}. #{last_name}"
188
184
  # end
@@ -227,19 +223,19 @@ module ActionView
227
223
  #
228
224
  # Example object structure for use with this method:
229
225
  #
226
+ # # attributes: id, name
230
227
  # class Continent < ActiveRecord::Base
231
228
  # has_many :countries
232
- # # attribs: id, name
233
229
  # end
234
230
  #
231
+ # # attributes: id, name, continent_id
235
232
  # class Country < ActiveRecord::Base
236
233
  # belongs_to :continent
237
- # # attribs: id, name, continent_id
238
234
  # end
239
235
  #
236
+ # # attributes: id, name, country_id
240
237
  # class City < ActiveRecord::Base
241
238
  # belongs_to :country
242
- # # attribs: id, name, country_id
243
239
  # end
244
240
  #
245
241
  # Sample usage:
@@ -258,7 +254,6 @@ module ActionView
258
254
  # <option value="2">Ireland</option>
259
255
  # </optgroup>
260
256
  # </select>
261
- #
262
257
  def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
263
258
  Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
264
259
  end
@@ -282,21 +277,27 @@ module ActionView
282
277
  # Finally, this method supports a <tt>:default</tt> option, which selects
283
278
  # a default ActiveSupport::TimeZone if the object's time zone is +nil+.
284
279
  #
285
- # time_zone_select("user", "time_zone", nil, include_blank: true)
280
+ # time_zone_select(:user, :time_zone, nil, include_blank: true)
286
281
  #
287
- # time_zone_select("user", "time_zone", nil, default: "Pacific Time (US & Canada)")
282
+ # time_zone_select(:user, :time_zone, nil, default: "Pacific Time (US & Canada)")
288
283
  #
289
- # time_zone_select("user", 'time_zone', ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
284
+ # time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
290
285
  #
291
- # time_zone_select("user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
286
+ # time_zone_select(:user, :time_zone, [ ActiveSupport::TimeZone["Alaska"], ActiveSupport::TimeZone["Hawaii"] ])
292
287
  #
293
- # time_zone_select("user", 'time_zone', /Australia/)
288
+ # time_zone_select(:user, :time_zone, /Australia/)
294
289
  #
295
- # time_zone_select("user", "time_zone", ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
290
+ # time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
296
291
  def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
297
292
  Tags::TimeZoneSelect.new(object, method, self, priority_zones, options, html_options).render
298
293
  end
299
294
 
295
+ # Returns select and option tags for the given object and method, using
296
+ # <tt>weekday_options_for_select</tt> to generate the list of option tags.
297
+ def weekday_select(object, method, options = {}, html_options = {}, &block)
298
+ Tags::WeekdaySelect.new(object, method, self, options, html_options, &block).render
299
+ end
300
+
300
301
  # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
301
302
  # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
302
303
  # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
@@ -593,6 +594,25 @@ module ActionView
593
594
  zone_options.safe_concat options_for_select(convert_zones[zones], selected)
594
595
  end
595
596
 
597
+ # Returns a string of option tags for the days of the week.
598
+ #
599
+ # Options:
600
+ # * <tt>:index_as_value</tt> - Defaults to false, set to true to use the indexes from
601
+ # `I18n.translate("date.day_names")` as the values. By default, Sunday is always 0.
602
+ # * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
603
+ # Defaults to :day_names, set to :abbr_day_names for abbreviations.
604
+ # * <tt>:beginning_of_week</tt> - Defaults to Date.beginning_of_week.
605
+ #
606
+ # NOTE: Only the option tags are returned, you have to wrap this call in
607
+ # a regular HTML select tag.
608
+ def weekday_options_for_select(selected = nil, index_as_value: false, day_format: :day_names, beginning_of_week: Date.beginning_of_week)
609
+ day_names = I18n.translate("date.#{day_format}")
610
+ day_names = day_names.map.with_index.to_a if index_as_value
611
+ day_names = day_names.rotate(Date::DAYS_INTO_WEEK.fetch(beginning_of_week))
612
+
613
+ options_for_select(day_names, selected)
614
+ end
615
+
596
616
  # Returns radio button tags for the collection of existing return values
597
617
  # of +method+ for +object+'s class. The value returned from calling
598
618
  # +method+ on the instance +object+ will be selected. If calling +method+
@@ -606,11 +626,14 @@ module ActionView
606
626
  # retrieve the value/text.
607
627
  #
608
628
  # Example object structure for use with this method:
629
+ #
609
630
  # class Post < ActiveRecord::Base
610
631
  # belongs_to :author
611
632
  # end
633
+ #
612
634
  # class Author < ActiveRecord::Base
613
635
  # has_many :posts
636
+ #
614
637
  # def name_with_initial
615
638
  # "#{first_name.first}. #{last_name}"
616
639
  # end
@@ -793,9 +816,9 @@ module ActionView
793
816
 
794
817
  def extract_values_from_collection(collection, value_method, selected)
795
818
  if selected.is_a?(Proc)
796
- collection.map do |element|
819
+ collection.filter_map do |element|
797
820
  element.public_send(value_method) if selected.call(element)
798
- end.compact
821
+ end
799
822
  else
800
823
  selected
801
824
  end
@@ -859,6 +882,18 @@ module ActionView
859
882
  @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options))
860
883
  end
861
884
 
885
+ # Wraps ActionView::Helpers::FormOptionsHelper#weekday_select for form builders:
886
+ #
887
+ # <%= form_for @user do |f| %>
888
+ # <%= f.weekday_select :weekday, include_blank: true %>
889
+ # <%= f.submit %>
890
+ # <% end %>
891
+ #
892
+ # Please refer to the documentation of the base helper for details.
893
+ def weekday_select(method, options = {}, html_options = {})
894
+ @template.weekday_select(@object_name, method, objectify_options(options), @default_html_options.merge(html_options))
895
+ end
896
+
862
897
  # Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders:
863
898
  #
864
899
  # <%= form_for @post do |f| %>
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cgi"
4
- require "action_view/helpers/tag_helper"
4
+ require "action_view/helpers/url_helper"
5
+ require "action_view/helpers/text_helper"
5
6
  require "active_support/core_ext/string/output_safety"
6
7
  require "active_support/core_ext/module/attribute_accessors"
7
- require "active_support/core_ext/symbol/starts_ends_with"
8
8
 
9
9
  module ActionView
10
10
  # = Action View Form Tag Helpers
11
- module Helpers #:nodoc:
11
+ module Helpers # :nodoc:
12
12
  # Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like
13
13
  # FormHelper does. Instead, you provide the names and values manually.
14
14
  #
@@ -62,6 +62,9 @@ module ActionView
62
62
  #
63
63
  # <%= form_tag('/posts', remote: true) %>
64
64
  # # => <form action="/posts" method="post" data-remote="true">
65
+
66
+ # form_tag(false, method: :get)
67
+ # # => <form method="get">
65
68
  #
66
69
  # form_tag('http://far.away.com/form', authenticity_token: false)
67
70
  # # form without authenticity token
@@ -78,6 +81,68 @@ module ActionView
78
81
  end
79
82
  end
80
83
 
84
+ # Generate an HTML <tt>id</tt> attribute value for the given name and
85
+ # field combination
86
+ #
87
+ # Return the value generated by the <tt>FormBuilder</tt> for the given
88
+ # attribute name.
89
+ #
90
+ # <%= label_tag :post, :title %>
91
+ # <%= text_field_tag :post, :title, aria: { describedby: field_id(:post, :title, :error) } %>
92
+ # <%= tag.span("is blank", id: field_id(:post, :title, :error) %>
93
+ #
94
+ # In the example above, the <tt><input type="text"></tt> element built by
95
+ # the call to <tt>text_field_tag</tt> declares an
96
+ # <tt>aria-describedby</tt> attribute referencing the <tt><span></tt>
97
+ # element, sharing a common <tt>id</tt> root (<tt>post_title</tt>, in this
98
+ # case).
99
+ def field_id(object_name, method_name, *suffixes, index: nil)
100
+ if object_name.respond_to?(:model_name)
101
+ object_name = object_name.model_name.singular
102
+ end
103
+
104
+ sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
105
+
106
+ sanitized_method_name = method_name.to_s.delete_suffix("?")
107
+
108
+ # a little duplication to construct fewer strings
109
+ if sanitized_object_name.empty?
110
+ sanitized_method_name
111
+ elsif suffixes.any?
112
+ [sanitized_object_name, index, sanitized_method_name, *suffixes].compact.join("_")
113
+ elsif index
114
+ "#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
115
+ else
116
+ "#{sanitized_object_name}_#{sanitized_method_name}"
117
+ end
118
+ end
119
+
120
+ # Generate an HTML <tt>name</tt> attribute value for the given name and
121
+ # field combination
122
+ #
123
+ # Return the value generated by the <tt>FormBuilder</tt> for the given
124
+ # attribute name.
125
+ #
126
+ # <%= text_field_tag :post, :title, name: field_name(:post, :title, :subtitle) %>
127
+ # <%# => <input type="text" name="post[title][subtitle]">
128
+ #
129
+ # <%= text_field_tag :post, :tag, name: field_name(:post, :tag, multiple: true) %>
130
+ # <%# => <input type="text" name="post[tag][]">
131
+ #
132
+ def field_name(object_name, method_name, *method_names, multiple: false, index: nil)
133
+ names = method_names.map! { |name| "[#{name}]" }.join
134
+
135
+ # a little duplication to construct fewer strings
136
+ case
137
+ when object_name.empty?
138
+ "#{method_name}#{names}#{multiple ? "[]" : ""}"
139
+ when index
140
+ "#{object_name}[#{index}][#{method_name}]#{names}#{multiple ? "[]" : ""}"
141
+ else
142
+ "#{object_name}[#{method_name}]#{names}#{multiple ? "[]" : ""}"
143
+ end
144
+ end
145
+
81
146
  # Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
82
147
  # choice selection box.
83
148
  #
@@ -167,8 +232,8 @@ module ActionView
167
232
  # * <tt>:size</tt> - The number of visible characters that will fit in the input.
168
233
  # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
169
234
  # * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
170
- # If set to true, use a translation is found in the current I18n locale
171
- # (through helpers.placeholders.<modelname>.<attribute>).
235
+ # If set to true, use the translation found in the current I18n locale
236
+ # (through helpers.placeholder.<modelname>.<attribute>).
172
237
  # * Any other key creates standard HTML attributes for the tag.
173
238
  #
174
239
  # ==== Examples
@@ -241,7 +306,7 @@ module ActionView
241
306
  # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
242
307
  # # type="hidden" value="" />
243
308
  def hidden_field_tag(name, value = nil, options = {})
244
- text_field_tag(name, value, options.merge(type: :hidden))
309
+ text_field_tag(name, value, options.merge(type: :hidden, autocomplete: "off"))
245
310
  end
246
311
 
247
312
  # Creates a file upload field. If you are using file uploads then you will also need
@@ -280,7 +345,7 @@ module ActionView
280
345
  # file_field_tag 'file', accept: 'text/html', class: 'upload', value: 'index.html'
281
346
  # # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
282
347
  def file_field_tag(name, options = {})
283
- text_field_tag(name, nil, convert_direct_upload_option_to_url(options.merge(type: :file)))
348
+ text_field_tag(name, nil, convert_direct_upload_option_to_url(name, options.merge(type: :file)))
284
349
  end
285
350
 
286
351
  # Creates a password field, a masked text field that will hide the users input behind a mask character.
@@ -417,16 +482,6 @@ module ActionView
417
482
  # * <tt>:disabled</tt> - If true, the user will not be able to use this input.
418
483
  # * Any other key creates standard HTML options for the tag.
419
484
  #
420
- # ==== Data attributes
421
- #
422
- # * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
423
- # drivers will provide a prompt with the question specified. If the user accepts,
424
- # the form is processed normally, otherwise no action is taken.
425
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
426
- # disabled version of the submit button when the form is submitted. This feature is
427
- # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
428
- # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
429
- #
430
485
  # ==== Examples
431
486
  # submit_tag
432
487
  # # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
@@ -437,15 +492,28 @@ module ActionView
437
492
  # submit_tag "Save edits", disabled: true
438
493
  # # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
439
494
  #
440
- # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
441
- # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
442
- #
443
495
  # submit_tag nil, class: "form_submit"
444
496
  # # => <input class="form_submit" name="commit" type="submit" />
445
497
  #
446
498
  # submit_tag "Edit", class: "edit_button"
447
499
  # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
448
500
  #
501
+ # ==== Deprecated: Rails UJS attributes
502
+ #
503
+ # Prior to Rails 7, Rails shipped with the JavaScript library called @rails/ujs on by default. Following Rails 7,
504
+ # this library is no longer on by default. This library integrated with the following options:
505
+ #
506
+ # * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
507
+ # drivers will provide a prompt with the question specified. If the user accepts,
508
+ # the form is processed normally, otherwise no action is taken.
509
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
510
+ # disabled version of the submit button when the form is submitted. This feature is
511
+ # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
512
+ # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
513
+ #
514
+ # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
515
+ # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
516
+ #
449
517
  # submit_tag "Save", data: { confirm: "Are you sure?" }
450
518
  # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
451
519
  #
@@ -470,17 +538,6 @@ module ActionView
470
538
  # use this input.
471
539
  # * Any other key creates standard HTML options for the tag.
472
540
  #
473
- # ==== Data attributes
474
- #
475
- # * <tt>confirm: 'question?'</tt> - If present, the
476
- # unobtrusive JavaScript drivers will provide a prompt with
477
- # the question specified. If the user accepts, the form is
478
- # processed normally, otherwise no action is taken.
479
- # * <tt>:disable_with</tt> - Value of this parameter will be
480
- # used as the value for a disabled version of the submit
481
- # button when the form is submitted. This feature is provided
482
- # by the unobtrusive JavaScript driver.
483
- #
484
541
  # ==== Examples
485
542
  # button_tag
486
543
  # # => <button name="button" type="submit">Button</button>
@@ -501,6 +558,20 @@ module ActionView
501
558
  # # <strong>Ask me!</strong>
502
559
  # # </button>
503
560
  #
561
+ # ==== Deprecated: Rails UJS attributes
562
+ #
563
+ # Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
564
+ # this library is no longer on by default. This library integrated with the following options:
565
+ #
566
+ # * <tt>confirm: 'question?'</tt> - If present, the
567
+ # unobtrusive JavaScript drivers will provide a prompt with
568
+ # the question specified. If the user accepts, the form is
569
+ # processed normally, otherwise no action is taken.
570
+ # * <tt>:disable_with</tt> - Value of this parameter will be
571
+ # used as the value for a disabled version of the submit
572
+ # button when the form is submitted. This feature is provided
573
+ # by the unobtrusive JavaScript driver.
574
+ #
504
575
  # button_tag "Save", data: { confirm: "Are you sure?" }
505
576
  # # => <button name="button" type="submit" data-confirm="Are you sure?">Save</button>
506
577
  #
@@ -677,6 +748,7 @@ module ActionView
677
748
  # * <tt>:min</tt> - The minimum acceptable value.
678
749
  # * <tt>:max</tt> - The maximum acceptable value.
679
750
  # * <tt>:step</tt> - The acceptable value granularity.
751
+ # * <tt>:include_seconds</tt> - Include seconds and ms in the output timestamp format (true by default).
680
752
  # * Otherwise accepts the same options as text_field_tag.
681
753
  def time_field_tag(name, value = nil, options = {})
682
754
  text_field_tag(name, value, options.merge(type: :time))
@@ -823,7 +895,7 @@ module ActionView
823
895
  # Use raw HTML to ensure the value is written as an HTML entity; it
824
896
  # needs to be the right character regardless of which encoding the
825
897
  # browser infers.
826
- '<input name="utf8" type="hidden" value="&#x2713;" />'.html_safe
898
+ '<input name="utf8" type="hidden" value="&#x2713;" autocomplete="off" />'.html_safe
827
899
  end
828
900
 
829
901
  private
@@ -832,13 +904,17 @@ module ActionView
832
904
  html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
833
905
  # The following URL is unescaped, this is just a hash of options, and it is the
834
906
  # responsibility of the caller to escape all the values.
835
- html_options["action"] = url_for(url_for_options)
907
+ if url_for_options == false || html_options["action"] == false
908
+ html_options.delete("action")
909
+ else
910
+ html_options["action"] = url_for(url_for_options)
911
+ end
836
912
  html_options["accept-charset"] = "UTF-8"
837
913
 
838
914
  html_options["data-remote"] = true if html_options.delete("remote")
839
915
 
840
916
  if html_options["data-remote"] &&
841
- !embed_authenticity_token_in_remote_forms &&
917
+ embed_authenticity_token_in_remote_forms == false &&
842
918
  html_options["authenticity_token"].blank?
843
919
  # The authenticity token is taken from the meta tag in this case
844
920
  html_options["authenticity_token"] = false
@@ -887,7 +963,7 @@ module ActionView
887
963
 
888
964
  def form_tag_with_body(html_options, content)
889
965
  output = form_tag_html(html_options)
890
- output << content
966
+ output << content.to_s if content
891
967
  output.safe_concat("</form>")
892
968
  end
893
969
 
@@ -911,9 +987,23 @@ module ActionView
911
987
  tag_options.delete("data-disable-with")
912
988
  end
913
989
 
914
- def convert_direct_upload_option_to_url(options)
990
+ def convert_direct_upload_option_to_url(name, options)
915
991
  if options.delete(:direct_upload) && respond_to?(:rails_direct_uploads_url)
916
992
  options["data-direct-upload-url"] = rails_direct_uploads_url
993
+
994
+ if options[:object] && options[:object].class.respond_to?(:reflect_on_attachment)
995
+ attachment_reflection = options[:object].class.reflect_on_attachment(name)
996
+
997
+ class_with_attachment = "#{options[:object].class.name.underscore}##{name}"
998
+ options["data-direct-upload-attachment-name"] = class_with_attachment
999
+
1000
+ service_name = attachment_reflection.options[:service_name] || ActiveStorage::Blob.service.name
1001
+ options["data-direct-upload-token"] = ActiveStorage::DirectUploadToken.generate_direct_upload_token(
1002
+ class_with_attachment,
1003
+ service_name,
1004
+ session
1005
+ )
1006
+ end
917
1007
  end
918
1008
  options
919
1009
  end
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_view/helpers/tag_helper"
4
-
5
3
  module ActionView
6
- module Helpers #:nodoc:
4
+ module Helpers # :nodoc:
7
5
  module JavaScriptHelper
8
6
  JS_ESCAPE_MAP = {
9
- '\\' => '\\\\',
7
+ "\\" => "\\\\",
10
8
  "</" => '<\/',
11
9
  "\r\n" => '\n',
12
10
  "\n" => '\n',
@@ -89,7 +87,7 @@ module ActionView
89
87
  content_tag("script", javascript_cdata_section(content), html_options)
90
88
  end
91
89
 
92
- def javascript_cdata_section(content) #:nodoc:
90
+ def javascript_cdata_section(content) # :nodoc:
93
91
  "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
94
92
  end
95
93
  end
@@ -6,7 +6,7 @@ require "active_support/number_helper"
6
6
 
7
7
  module ActionView
8
8
  # = Action View Number Helpers
9
- module Helpers #:nodoc:
9
+ module Helpers # :nodoc:
10
10
  # Provides methods for converting numbers into formatted strings.
11
11
  # Methods are provided for phone numbers, currency, percentage,
12
12
  # precision, positional notation, file size and pretty printing.
@@ -448,9 +448,8 @@ module ActionView
448
448
  end
449
449
 
450
450
  def parse_float(number, raise_error)
451
- Float(number)
452
- rescue ArgumentError, TypeError
453
- raise InvalidNumberError, number if raise_error
451
+ result = Float(number, exception: false)
452
+ raise InvalidNumberError, number if result.nil? && raise_error
454
453
  end
455
454
  end
456
455
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  require "active_support/core_ext/string/output_safety"
4
4
 
5
- module ActionView #:nodoc:
5
+ module ActionView # :nodoc:
6
6
  # = Action View Raw Output Helper
7
- module Helpers #:nodoc:
7
+ module Helpers # :nodoc:
8
8
  module OutputSafetyHelper
9
9
  # This method outputs without escaping a string. Since escaping tags is
10
10
  # now default, this can be used when you don't want Rails to automatically
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- module Helpers #:nodoc:
4
+ module Helpers # :nodoc:
5
5
  # = Action View Rendering
6
6
  #
7
7
  # Implements methods that allow rendering from a view context.
@@ -4,7 +4,7 @@ require "rails-html-sanitizer"
4
4
 
5
5
  module ActionView
6
6
  # = Action View Sanitize Helpers
7
- module Helpers #:nodoc:
7
+ module Helpers # :nodoc:
8
8
  # The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
9
9
  # These helper methods extend Action View making them callable within your template files.
10
10
  module SanitizeHelper
@@ -121,7 +121,7 @@ module ActionView
121
121
  self.class.link_sanitizer.sanitize(html)
122
122
  end
123
123
 
124
- module ClassMethods #:nodoc:
124
+ module ClassMethods # :nodoc:
125
125
  attr_writer :full_sanitizer, :link_sanitizer, :safe_list_sanitizer
126
126
 
127
127
  def sanitizer_vendor