actionview 7.0.0.alpha2 → 7.0.0

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10a4345b17834e9593bf0b42ccd2170b3cbf15e12f90b46d5022d3f42debe197
4
- data.tar.gz: fe8446b4f105e3dd0b071fb3bd2da626d62221bc10ef3da4f2ba67165e6c4f39
3
+ metadata.gz: 4404695c53394a381070413d888aa3a233c9f2b20f0f9d95b5d09c7d677bf14b
4
+ data.tar.gz: e2d825223979a9ce8c17024d6f74389f03c7161872bbba807c2cd760769b0922
5
5
  SHA512:
6
- metadata.gz: eac9c7426ef7c9562fcb5da319e2b553e7703f0ecd3eb7341120d69abf4dd52fe3de8e9f4f179de8c4ed91864ddcf47bb5c80a0c727b4b1bc1063a996cad6527
7
- data.tar.gz: 9ea9389303fa84db67be4603551b2fa71542ede511479f9f7430a55b2d519b4c88305b167167849d19b5b249e33d45a5ab666a860536b9843a7aeed7cfbbcd40
6
+ metadata.gz: 3c2ce1c485c81aa6a4b268e6b1eabb19123b5aebf9b76855c0be654c19c7d5d4ff66b676759352a8978910540ddfb20fd66e9fd95a3cc1887af0cd435d028914
7
+ data.tar.gz: 4ea433d6ba6b950f1f94b3d0e5c1cfd2493d5fb3f56fcd8d904bc0cf06603118443ccc121880eb8bbd7e0920347c6bda74809858a6cd297038e39ec115fed70b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,159 @@
1
+ ## Rails 7.0.0 (December 15, 2021) ##
2
+
3
+ * Support `include_hidden:` option in calls to
4
+ `ActionView::Helper::FormBuilder#file_field` with `multiple: true` to
5
+ support submitting an empty collection of files.
6
+
7
+ ```ruby
8
+ form.file_field :attachments, multiple: true
9
+ # => <input type="hidden" autocomplete="off" name="post[attachments][]" value="">
10
+ <input type="file" multiple="multiple" id="post_attachments" name="post[attachments][]">
11
+
12
+ form.file_field :attachments, multiple: true, include_hidden: false
13
+ # => <input type="file" multiple="multiple" id="post_attachments" name="post[attachments][]">
14
+ ```
15
+
16
+ *Sean Doyle*
17
+
18
+ * Fix `number_with_precision(raise: true)` always raising even on valid numbers.
19
+
20
+ *Pedro Moreira*
21
+
22
+
23
+ ## Rails 7.0.0.rc3 (December 14, 2021) ##
24
+
25
+ * No changes.
26
+
27
+
28
+ ## Rails 7.0.0.rc2 (December 14, 2021) ##
29
+
30
+ * No changes.
31
+
32
+ ## Rails 7.0.0.rc1 (December 06, 2021) ##
33
+
34
+ * Support `fields model: [@nested, @model]` the same way as `form_with model:
35
+ [@nested, @model]`.
36
+
37
+ *Sean Doyle*
38
+
39
+ * Infer HTTP verb `[method]` from a model or Array with model as the first
40
+ argument to `button_to` when combined with a block:
41
+
42
+ ```ruby
43
+ button_to(Workshop.find(1)){ "Update" }
44
+ #=> <form method="post" action="/workshops/1" class="button_to">
45
+ #=> <input type="hidden" name="_method" value="patch" autocomplete="off" />
46
+ #=> <button type="submit">Update</button>
47
+ #=> </form>
48
+
49
+ button_to([ Workshop.find(1), Session.find(1) ]) { "Update" }
50
+ #=> <form method="post" action="/workshops/1/sessions/1" class="button_to">
51
+ #=> <input type="hidden" name="_method" value="patch" autocomplete="off" />
52
+ #=> <button type="submit">Update</button>
53
+ #=> </form>
54
+ ```
55
+
56
+ *Sean Doyle*
57
+
58
+ * Support passing a Symbol as the first argument to `FormBuilder#button`:
59
+
60
+ ```ruby
61
+ form.button(:draft, value: true)
62
+ # => <button name="post[draft]" value="true" type="submit">Create post</button>
63
+
64
+ form.button(:draft, value: true) do
65
+ content_tag(:strong, "Save as draft")
66
+ end
67
+ # => <button name="post[draft]" value="true" type="submit">
68
+ # <strong>Save as draft</strong>
69
+ # </button>
70
+ ```
71
+
72
+ *Sean Doyle*
73
+
74
+ * Introduce the `field_name` view helper, along with the
75
+ `FormBuilder#field_name` counterpart:
76
+
77
+ ```ruby
78
+ form_for @post do |f|
79
+ f.field_tag :tag, name: f.field_name(:tag, multiple: true)
80
+ # => <input type="text" name="post[tag][]">
81
+ end
82
+ ```
83
+
84
+ *Sean Doyle*
85
+
86
+ * Execute the `ActionView::Base.field_error_proc` within the context of the
87
+ `ActionView::Base` instance:
88
+
89
+ ```ruby
90
+ config.action_view.field_error_proc = proc { |html| content_tag(:div, html, class: "field_with_errors") }
91
+ ```
92
+
93
+ *Sean Doyle*
94
+
95
+ * Add support for `button_to ..., authenticity_token: false`
96
+
97
+ ```ruby
98
+ button_to "Create", Post.new, authenticity_token: false
99
+ # => <form class="button_to" method="post" action="/posts"><button type="submit">Create</button></form>
100
+
101
+ button_to "Create", Post.new, authenticity_token: true
102
+ # => <form class="button_to" method="post" action="/posts"><button type="submit">Create</button><input type="hidden" name="form_token" value="abc123..." autocomplete="off" /></form>
103
+
104
+ button_to "Create", Post.new, authenticity_token: "secret"
105
+ # => <form class="button_to" method="post" action="/posts"><button type="submit">Create</button><input type="hidden" name="form_token" value="secret" autocomplete="off" /></form>
106
+ ```
107
+
108
+ *Sean Doyle*
109
+
110
+ * Support rendering `<form>` elements _without_ `[action]` attributes by:
111
+
112
+ * `form_with url: false` or `form_with ..., html: { action: false }`
113
+ * `form_for ..., url: false` or `form_for ..., html: { action: false }`
114
+ * `form_tag false` or `form_tag ..., action: false`
115
+ * `button_to "...", false` or `button_to(false) { ... }`
116
+
117
+ *Sean Doyle*
118
+
119
+ * Add `:day_format` option to `date_select`
120
+
121
+ date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
122
+ # generates day options like <option value="1">1st</option>\n<option value="2">2nd</option>...
123
+
124
+ *Shunichi Ikegami*
125
+
126
+ * Allow `link_to` helper to infer link name from `Model#to_s` when it
127
+ is used with a single argument:
128
+
129
+ link_to @profile
130
+ #=> <a href="/profiles/1">Eileen</a>
131
+
132
+ This assumes the model class implements a `to_s` method like this:
133
+
134
+ class Profile < ApplicationRecord
135
+ # ...
136
+ def to_s
137
+ name
138
+ end
139
+ end
140
+
141
+ Previously you had to supply a second argument even if the `Profile`
142
+ model implemented a `#to_s` method that called the `name` method.
143
+
144
+ link_to @profile, @profile.name
145
+ #=> <a href="/profiles/1">Eileen</a>
146
+
147
+ *Olivier Lacan*
148
+
149
+ * Support svg unpaired tags for `tag` helper.
150
+
151
+ tag.svg { tag.use('href' => "#cool-icon") }
152
+ # => <svg><use href="#cool-icon"></svg>
153
+
154
+ *Oleksii Vasyliev*
155
+
156
+
1
157
  ## Rails 7.0.0.alpha2 (September 15, 2021) ##
2
158
 
3
159
  * No changes.
@@ -142,7 +142,7 @@ module ActionView # :nodoc:
142
142
  include Helpers, ::ERB::Util, Context
143
143
 
144
144
  # Specify the proc used to decorate input tags that refer to attributes with errors.
145
- cattr_accessor :field_error_proc, default: Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
145
+ cattr_accessor :field_error_proc, default: Proc.new { |html_tag, instance| content_tag :div, html_tag, class: "field_with_errors" }
146
146
 
147
147
  # How to complete the streaming when an exception occurs.
148
148
  # This is our best guess: first try to close the attribute, then the tag.
@@ -156,9 +156,6 @@ module ActionView # :nodoc:
156
156
  # Specify default_formats that can be rendered.
157
157
  cattr_accessor :default_formats
158
158
 
159
- # Specify whether an error should be raised for missing translations
160
- cattr_accessor :raise_on_missing_translations, default: false
161
-
162
159
  # Specify whether submit_tag should automatically disable on click
163
160
  cattr_accessor :automatically_disable_submit_tag, default: true
164
161
 
@@ -4,7 +4,7 @@ module ActionView
4
4
  class CacheExpiry
5
5
  class Executor
6
6
  def initialize(watcher:)
7
- @execution_lock = Concurrent::ReadWriteLock.new
7
+ @execution_lock = Concurrent::ReentrantReadWriteLock.new
8
8
  @cache_expiry = ViewModificationWatcher.new(watcher: watcher) do
9
9
  clear_cache
10
10
  end
@@ -10,7 +10,7 @@ module ActionView
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
12
  TINY = 0
13
- PRE = "alpha2"
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -27,7 +27,7 @@ module ActionView
27
27
 
28
28
  def error_wrapping(html_tag)
29
29
  if object_has_errors?
30
- Base.field_error_proc.call(html_tag, self)
30
+ @template_object.instance_exec(html_tag, self, &Base.field_error_proc)
31
31
  else
32
32
  html_tag
33
33
  end
@@ -258,14 +258,14 @@ module ActionView
258
258
  #
259
259
  # The helper gets the name of the favicon file as first argument, which
260
260
  # defaults to "favicon.ico", and also supports +:rel+ and +:type+ options
261
- # to override their defaults, "shortcut icon" and "image/x-icon"
261
+ # to override their defaults, "icon" and "image/x-icon"
262
262
  # respectively:
263
263
  #
264
264
  # favicon_link_tag
265
- # # => <link href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon" />
265
+ # # => <link href="/assets/favicon.ico" rel="icon" type="image/x-icon" />
266
266
  #
267
267
  # favicon_link_tag 'myicon.ico'
268
- # # => <link href="/assets/myicon.ico" rel="shortcut icon" type="image/x-icon" />
268
+ # # => <link href="/assets/myicon.ico" rel="icon" type="image/x-icon" />
269
269
  #
270
270
  # Mobile Safari looks for a different link tag, pointing to an image that
271
271
  # will be used if you add the page to the home screen of an iOS device.
@@ -275,7 +275,7 @@ module ActionView
275
275
  # # => <link href="/assets/mb-icon.png" rel="apple-touch-icon" type="image/png" />
276
276
  def favicon_link_tag(source = "favicon.ico", options = {})
277
277
  tag("link", {
278
- rel: "shortcut icon",
278
+ rel: "icon",
279
279
  type: "image/x-icon",
280
280
  href: path_to_image(source, skip_pipeline: options.delete(:skip_pipeline))
281
281
  }.merge!(options.symbolize_keys))
@@ -542,7 +542,7 @@ module ActionView
542
542
  MAX_HEADER_SIZE = 8_000 # Some HTTP client and proxies have a 8kiB header limit
543
543
  def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
544
544
  return if preload_links.empty?
545
- return if response.sending?
545
+ return if respond_to?(:response) && response.sending?
546
546
 
547
547
  if respond_to?(:request) && request
548
548
  request.send_early_hints("Link" => preload_links.join("\n"))
@@ -121,7 +121,7 @@ module ActionView
121
121
  URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i
122
122
 
123
123
  # This is the entry point for all assets.
124
- # When using the asset pipeline (i.e. sprockets and sprockets-rails), the
124
+ # When using an asset pipeline gem (e.g. propshaft or sprockets-rails), the
125
125
  # behavior is "enhanced". You can bypass the asset pipeline by passing in
126
126
  # <tt>skip_pipeline: true</tt> to the options.
127
127
  #
@@ -130,7 +130,7 @@ module ActionView
130
130
  # === With the asset pipeline
131
131
  #
132
132
  # All options passed to +asset_path+ will be passed to +compute_asset_path+
133
- # which is implemented by sprockets-rails.
133
+ # which is implemented by asset pipeline gems.
134
134
  #
135
135
  # asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"
136
136
  # asset_path('application.js', host: 'example.com') # => "//example.com/assets/application.js"
@@ -292,19 +292,20 @@ module ActionView
292
292
  controller.write_fragment(name, fragment, options)
293
293
  end
294
294
 
295
- class CachingRegistry
296
- extend ActiveSupport::PerThreadRegistry
295
+ module CachingRegistry # :nodoc:
296
+ extend self
297
297
 
298
- attr_accessor :caching
299
- alias caching? caching
298
+ def caching?
299
+ ActiveSupport::IsolatedExecutionState[:action_view_caching] ||= false
300
+ end
300
301
 
301
- def self.track_caching
302
- caching_was = self.caching
303
- self.caching = true
302
+ def track_caching
303
+ caching_was = ActiveSupport::IsolatedExecutionState[:action_view_caching]
304
+ ActiveSupport::IsolatedExecutionState[:action_view_caching] = true
304
305
 
305
306
  yield
306
307
  ensure
307
- self.caching = caching_was
308
+ ActiveSupport::IsolatedExecutionState[:action_view_caching] = caching_was
308
309
  end
309
310
  end
310
311
  end
@@ -206,6 +206,7 @@ module ActionView
206
206
  # you are creating new record. While editing existing record, <tt>:end_year</tt> defaults to
207
207
  # the current selected year plus 5.
208
208
  # * <tt>:year_format</tt> - Set format of years for year select. Lambda should be passed.
209
+ # * <tt>:day_format</tt> - Set format of days for day select. Lambda should be passed.
209
210
  # * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day
210
211
  # as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
211
212
  # first of the given month in order to not create invalid dates like 31 February.
@@ -279,6 +280,9 @@ module ActionView
279
280
  # # Generates a date select with custom year format.
280
281
  # date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
281
282
  #
283
+ # # Generates a date select with custom day format.
284
+ # date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
285
+ #
282
286
  # The selects are prepared for multi-parameter assignment to an Active Record object.
283
287
  #
284
288
  # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
@@ -811,7 +815,7 @@ module ActionView
811
815
  if @options[:use_hidden] || @options[:discard_day]
812
816
  build_hidden(:day, day || 1)
813
817
  else
814
- build_options_and_select(:day, day, start: 1, end: 31, leading_zeros: false, use_two_digit_numbers: @options[:use_two_digit_numbers])
818
+ build_select(:day, build_day_options(day))
815
819
  end
816
820
  end
817
821
 
@@ -899,6 +903,27 @@ module ActionView
899
903
  I18n.translate(key, locale: @options[:locale])
900
904
  end
901
905
 
906
+ # Looks up day names by number.
907
+ #
908
+ # day_name(1) # => 1
909
+ #
910
+ # If the <tt>use_two_digit_numbers: true</tt> option is passed to DateTimeSelector:
911
+ #
912
+ # day_name(1) # => "01"
913
+ #
914
+ # If the <tt>day_format: ->(day) { day.ordinalize }</tt> option is passed to DateTimeSelector:
915
+ #
916
+ # day_name(1) # => "1st"
917
+ def day_name(number)
918
+ if day_format_lambda = @options[:day_format]
919
+ day_format_lambda.call(number)
920
+ elsif @options[:use_two_digit_numbers]
921
+ "%02d" % number
922
+ else
923
+ number
924
+ end
925
+ end
926
+
902
927
  # Looks up month names by number (1-based):
903
928
  #
904
929
  # month_name(1) # => "January"
@@ -1011,6 +1036,35 @@ module ActionView
1011
1036
  (select_options.join("\n") + "\n").html_safe
1012
1037
  end
1013
1038
 
1039
+ # Build select option HTML for day.
1040
+ # build_day_options(2)
1041
+ # => "<option value="1">1</option>
1042
+ # <option value="2" selected="selected">2</option>
1043
+ # <option value="3">3</option>..."
1044
+ #
1045
+ # If <tt>day_format: ->(day) { day.ordinalize }</tt> option is passed to DateTimeSelector
1046
+ # build_day_options(2)
1047
+ # => "<option value="1">1st</option>
1048
+ # <option value="2" selected="selected">2nd</option>
1049
+ # <option value="3">3rd</option>..."
1050
+ #
1051
+ # If <tt>use_two_digit_numbers: true</tt> option is passed to DateTimeSelector
1052
+ # build_day_options(2)
1053
+ # => "<option value="1">01</option>
1054
+ # <option value="2" selected="selected">02</option>
1055
+ # <option value="3">03</option>..."
1056
+ def build_day_options(selected)
1057
+ select_options = []
1058
+ (1..31).each do |value|
1059
+ tag_options = { value: value }
1060
+ tag_options[:selected] = "selected" if selected == value
1061
+ text = day_name(value)
1062
+ select_options << content_tag("option", text, tag_options)
1063
+ end
1064
+
1065
+ (select_options.join("\n") + "\n").html_safe
1066
+ end
1067
+
1014
1068
  # Build select option HTML for year.
1015
1069
  # If <tt>year_format</tt> option is not passed
1016
1070
  # build_year_options(1998, start: 1998, end: 2000)
@@ -1101,7 +1155,8 @@ module ActionView
1101
1155
  type: "hidden",
1102
1156
  id: input_id_from_type(type),
1103
1157
  name: input_name_from_type(type),
1104
- value: value
1158
+ value: value,
1159
+ autocomplete: "off"
1105
1160
  }.merge!(@html_options.slice(:disabled))
1106
1161
  select_options[:disabled] = "disabled" if @options[:disabled]
1107
1162